{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qN8P0AnTnAhh"
      },
      "source": [
        "##### Copyright 2019 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "p8SrVqkmnDQv"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "AftvNA5VMemJ"
      },
      "source": [
        "# 이미지 분류를 위한 Federated Learning"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "coAumH42q9nz"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/federated/tutorials/federated_learning_for_image_classification\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">TensorFlow.org에서 보기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ko/federated/tutorials/federated_learning_for_image_classification.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Google Colab에서 실행하기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ko/federated/tutorials/federated_learning_for_image_classification.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub에서소스 보기</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Zs2LgZBOMt4M"
      },
      "source": [
        "**참고**: 이 colab은 <code>tensorflow_federated</code> pip 패키지의 <a>최신 릴리즈 버전</a>에서 동작하는 것으로 확인되었지만, Tensorflow Federated 프로젝트는 아직 릴리즈 전 개발 중이며 `master`에서 동작하지 않을 수 있습니다.\n",
        "\n",
        "이 튜토리얼에서는 고전적인 MNIST 훈련 예제를 사용하여 TFF의 Federated Learning(FL) API 레이어(`tff.learning` - TensorFlow에서 구현된 사용자 제공 모델에 대해 페더레이션 훈련과 같은 일반적인 유형의 페더레이션 학습 작업을 수행하는 데 사용할 수 있는 상위 수준의 인터페이스 세트)를 소개합니다.\n",
        "\n",
        "이 튜토리얼과 Federated Learning API는 주로 자신의 TensorFlow 모델을 TFF에 연결하여 후자를 대부분 블랙 박스로 취급하려는 사용자를 대상으로 합니다. TFF에 대한 심층적인 이해와 자신의 페더레이션 학습 알고리즘을 구현하는 방법은 FC Core API 튜토리얼 - [사용자 정의 페더레이션 알고리즘 1부](custom_federated_algorithms_1.ipynb) 및 [2부](custom_federated_algorithms_2.ipynb)를 참조하세요.\n",
        "\n",
        "<code>tff.learning</code>에 대한 자세한 내용은 <a>Text Generation용 Federated Learning</a> 튜토리얼에서 계속하세요. 반복 모델을 다루는 것 외에도 Keras를 사용한 평가와 결합된 페더레이션 학습을 통해 구체화를 위한 사전 훈련되고 직렬화된 Keras 모델을 로드하는 방법을 보여줍니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MnUwFbCAKB2r"
      },
      "source": [
        "## 시작하기 전에\n",
        "\n",
        "시작하기 전에 다음을 실행하여 환경이 올바르게 설정되었는지 확인합니다. 인사말이 표시되지 않으면 [설치](../install.md) 가이드에서 지침을 참조하세요. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ZrGitA_KnRO0"
      },
      "outputs": [],
      "source": [
        "#@test {\"skip\": true}\n",
        "!pip install --quiet --upgrade tensorflow_federated_nightly\n",
        "!pip install --quiet --upgrade nest_asyncio\n",
        "\n",
        "import nest_asyncio\n",
        "nest_asyncio.apply()\n",
        "\n",
        "%load_ext tensorboard"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "8BKyHkMxKHfV"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "b'Hello, World!'"
            ]
          },
          "execution_count": 3,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "import collections\n",
        "\n",
        "import numpy as np\n",
        "import tensorflow as tf\n",
        "import tensorflow_federated as tff\n",
        "\n",
        "np.random.seed(0)\n",
        "\n",
        "tff.federated_computation(lambda: 'Hello, World!')()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5Cyy2AWbLMKj"
      },
      "source": [
        "## 입력 데이터 준비하기\n",
        "\n",
        "데이터부터 시작하겠습니다. 페더레이션 학습에는 페더레이션 데이터세트, 즉 여러 사용자의 데이터 모음이 필요합니다. 페더레이션 데이터는 일반적으로 고유한 문제를 제기하는 비 [i.i.d.](https://en.wikipedia.org/wiki/Independent_and_identically_distributed_random_variables)입니다.\n",
        "\n",
        "실험을 용이하게 하기 위해 [Leaf](https://www.nist.gov/srd/nist-special-database-19)를 사용하여 재처리된 [원래 NIST 데이터세트](https://github.com/TalwalkarLab/leaf)의 버전이 포함된 MNIST의 페더레이션 버전을 포함하여 몇 개의 데이터세트로 TFF 리포지토리를 시드하여 데이터가 원래 숫자 작성자에 의해 입력되도록 합니다. 작성자마다 고유한 스타일이 있기 때문에 이 데이터세트는 페더레이션 데이터세트에서 예상되는 non-i.i.d. 동작의 종류를 보여줍니다.\n",
        "\n",
        "로드하는 방법은 다음과 같습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "NayDhCX6SjwE"
      },
      "outputs": [],
      "source": [
        "emnist_train, emnist_test = tff.simulation.datasets.emnist.load_data()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "yeX8BKgPfeFw"
      },
      "source": [
        "`load_data()`가 반환하는 데이터세트는 사용자 세트를 열거하고 특정 사용자의 데이터를 나타내는 `tf.data.Dataset`를 구성하고 개별 요소의 구조를 쿼리할 수 있는 인터페이스인 `tff.simulation.ClientData`의 인스턴스입니다. 이 인터페이스를 사용하여 데이터세트의 내용을 탐색하는 방법은 다음과 같습니다. 이 인터페이스를 사용하면 클라이언트 ID를 반복할 수 있지만, 이는 시뮬레이션 데이터의 특성일 뿐입니다. 곧 살펴보겠지만, 클라이언트 ID는 페더레이션 학습 프레임워크에서 사용되지 않습니다. 클라이언트 ID의 유일한 목적은 시뮬레이션을 위해 데이터의 하위 집합을 선택할 수 있도록 하는 것입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kN4-U5nJgKig"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "3383"
            ]
          },
          "execution_count": 5,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "len(emnist_train.client_ids)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ZyCzIrSegT62"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "OrderedDict([('pixels', TensorSpec(shape=(28, 28), dtype=tf.float32, name=None)), ('label', TensorSpec(shape=(), dtype=tf.int32, name=None))])"
            ]
          },
          "execution_count": 6,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "emnist_train.element_type_structure"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "EsvSXGEMgd9G"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "1"
            ]
          },
          "execution_count": 7,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "example_dataset = emnist_train.create_tf_dataset_for_client(\n",
        "    emnist_train.client_ids[0])\n",
        "\n",
        "example_element = next(iter(example_dataset))\n",
        "\n",
        "example_element['label'].numpy()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "OmLV0nfMg98V"
      },
      "outputs": [
        {
          "data": {
            "image/png": "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\nfTpx4oSGh4fl8/kUDAZ19OjRnA8LIHvSxr927Vo55x67vK2tLScDAcgPXuEHGEX8gFHEDxhF/IBR\nxA8YRfyAUcQPGEX8gFHEDxhF/IBRxA8YRfyAUcQPGEX8gFE+96T36+bIsmXLFAwG575PJBJF+9Fe\nxTpbsc4lMVumsjnb2NiYpqen53XdvMb//8LhsDzPK9TuUyrW2Yp1LonZMlWo2XjaDxhF/IBRpT09\nPT2FHKC5ubmQu0+pWGcr1rkkZstUIWYr6M/8AAqHp/2AUQWJf2BgQC+//LJqamrU29tbiBGSCgaD\ncx9THg6HCzpLV1eX/H7/I2si3Lp1S5FIRLW1tYpEIkmXSSvEbMWycnOylaULfeyKbsVrl2cPHjxw\n1dXVbnR01P3999+usbHRXblyJd9jJPXiiy+6RCJR6DGcc8798MMP7tKlS66urm7uso8++sjt37/f\nOefc/v373ccff1w0s3366afuiy++KMg8/+vmzZvu0qVLzjnn/vrrL1dbW+uuXLlS8GOXbK5CHbe8\nP/IPDQ2ppqZG1dXVWrRokbZs2aL+/v58j/FUaGlp0dKlSx+5rL+/X52dnZKkzs5OnT59uhCjPXG2\nYhEIBLRq1SpJj64sXehjl2yuQsl7/BMTE1qxYsXc91VVVUW15LfP59OGDRvU3NysWCxW6HEeMzk5\nObdkeiAQ0NTUVIEnetR8Vm7Op/9dWbqYjl0mK15nW97jd084ueDz+fI9RlKDg4P65ZdfdPbsWR05\nckQ//vhjoUd6asx35eZ8+f+VpYtFpiteZ1ve46+qqtL4+Pjc9zdu3FBlZWW+x0jqP7P4/X5t2rSp\n6FYfrqiomFskNR6Py+/3F3ii/yqmlZuTrSxd6GNXTCte5z3+1atXa2RkRNevX9e9e/d08uRJtbe3\n53uMJ7p7965u37499/W5c+eKbvXh9vZ29fX1SZL6+vq0cePGAk/0X8WycrNLsrJ0oY9dsrkKdtzy\n/itG59yZM2dcbW2tq66udp9//nkhRnii0dFR19jY6BobG92rr75a8Nm2bNninn/+eVdWVuaWL1/u\nvv76azc9Pe3Wr1/vampq3Pr1692ff/5ZNLO9++67rr6+3jU0NLi33nrL3bx5syCz/fTTT06Sa2ho\ncCtXrnQrV650Z86cKfixSzZXoY4br/ADjOIVfoBRxA8YRfyAUcQPGEX8gFHEDxhF/IBRxA8Y9S85\nOQzW0CUnRwAAAABJRU5ErkJggg==\n",
            "text/plain": [
              "<Figure size 600x400 with 1 Axes>"
            ]
          },
          "metadata": {
            "tags": []
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "from matplotlib import pyplot as plt\n",
        "plt.imshow(example_element['pixels'].numpy(), cmap='gray', aspect='equal')\n",
        "plt.grid(False)\n",
        "_ = plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GGnxdUp8Cj5h"
      },
      "source": [
        "### 페더레이션 데이터의 이질성 탐색하기\n",
        "\n",
        "페더레이션 데이터는 일반적으로 비 [i.i.d.](https://en.wikipedia.org/wiki/Independent_and_identically_distributed_random_variables)이며, 사용자는 일반적으로 사용 패턴에 따라 데이터 분포가 다릅니다. 일부 클라이언트는 기기에 훈련 예제가 적어 로컬에서 데이터가 부족할 수 있지만, 일부 클라이언트는 충분한 훈련 예제를 가지고 있습니다. 사용 가능한 EMNIST 데이터를 사용하여 페더레이션 시스템의 일반적인 데이터 이질성 개념을 살펴보겠습니다. 고객 데이터에 대한 이 심층 분석은 모든 데이터를 로컬에서 사용할 수 있는 시뮬레이션 환경이기 때문에 당사만 사용할 수 있다는 점에 유의하는 것이 중요합니다. 실제 운영 페더레이션 환경에서는 단일 클라이언트의 데이터를 검사할 수 없습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "77mx33vXFrqd"
      },
      "source": [
        "먼저, 하나의 시뮬레이션 기기에서 예제에 대한 느낌을 얻기 위해 한 클라이언트의 데이터를 샘플링해 보겠습니다. 당사가 사용하는 데이터세트는 고유한 작성자가 입력했기 때문에 한 클라이언트의 데이터는 한 사용자의 고유한 \"사용 패턴\"을 시뮬레이션하여 0부터 9까지의 숫자 샘플에 대한 한 사람의 손글씨를 나타냅니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "PfRva0fsFfSX"
      },
      "outputs": [
        {
          "data": {
            "image/png": "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\nxcSJEwFYb731APjFL37BSiutBEDLli0r9t70//PVV18B5TH43XffAbDXXnvRvn17wOtiJaWPWP3Y\nTfaXX34JlK+H4Tp58MEHx+PTOOZDqVRabAzGjBkDwLhx4wD4xz/+wYQJEwC44447ANhuu+28RjaT\nxd3WNhXH77//HoAPP/wQKMfzl7/8JVtttRXg+qZSlnQOXLBgAQAtWrRYotf/K/hJkCRJkiRJylC1\n3aqSO6WffPIJAM899xwQZQ9Hjx4NwKeffgqUM4zjxo2Ld73NKOZDoVBotPP91FNP8ac//QmA8ePH\nA/DZZ58BcO655/LHP/4RyN4519LT1PiZNWsWQLz7ffXVV/Pqq68C0Q44wMorrwzAWmutRY8ePZrt\n/aosndVPjp8Qr5dffhmAYcOGxdVfIcvfqlUrAC6//PJGf1OVt/rqq7PzzjsD5R3Q1q1bxz8/5JBD\ngPIuufNn5SWPWgG89NJL/OUvfwGgT58+AFx55ZW89NJLQHn+7dChAwBz5szhoosuAqxcqKTwb56s\nPAmVe88//zwADzzwAO+88w4QxS1pl112sQIlJ5L//qFS6NZbbwWi+A4bNgwoV7qHeXSvvfbizDPP\nBGDLLbeM/5b3Gs1jceMlVEK/++67AAwfPpw33ngDKM+pG264IQBt27aNK1Bc31RGiGVYe86cOZPX\nXnsNKK9tJk2aFJ8yWXXVVQHia2fXrl2X2r2+o1mSJEmSJClD1fRASWfi77vvPgBuueWWeHe0Xbt2\nQLTTfdRRRwFw2223AdGOHETVKeEcePhbZvcrI7n7GXa7TzjhBCCqGAo7qLvtthsAvXv3BqI4h90d\nY9f80mMx/H+vXr3inbPtttsu/tmBBx4IQMeOHZv7raoJyfPc8+fPB+Css84C4OGHH47P5u+4444A\nnHrqqXTq1Akony8NvaTC/ysfkjstH330EQCbbbYZANdccw177LEHEO3KgBUoeZKOxVlnncWNN94I\nEPf86tGjB/vttx8Ae+65JwBrr712c79VpSTn1ClTpgAwZMgQAAYPHhxXm4R5s1evXnFV0THHHAMQ\nz7H333+/47LC0s3wZ8+eHVd6ff3110C0xglr0q233hqIemZAVF2r5pVcl06bNg0or0/ee+89AM4+\n++y4SjpUBm222Wb86le/avC9NdZYo/neuBopFApxtUioMrnkkkuAaCyGatpQHXTwwQfzt7/9DSj3\nBgs9iDp27Bh/NqxAkSRJkiRJamZVUYGSzO6H3dF9990XgO233z7O4IfsLxD3yLj33nsB4rOKW221\nlb1PKuTHzvM++uij3HTTTQAcf/zxABx22GHubudQcrqYOXMmAIcffjgAyy+/PA888ABQ3jFd3N9I\nPg7QnbalL/x719TUxN3m9957b6DcK+r888+Pd7h33XXXJfqbzqP5UV9fD0Tn8wcMGADAH/7wB6C8\nc6p8WbRoEVDumTF06FAAjjvuOO68806g3AOlqYrL5JxsRWZlJPu4XX/99UC530mXLl046KCDAOL+\ne0BcldKzZ0+AuG/fBhtssNR2TLVk0hVAL7/8Mvvssw8QVRQB7L///pm/n/wbWrqS175DDz0UKK9r\n7rrrLgCmTZsWV+4tLi7JtZJzavNL3vNPmjSpwdeWLVvGFe7hNAlET2eF8v1IWP801WPzX6Uqmsgm\nP8Bt2rQBYOzYsT/6+kGDBtG/f3+gfJEKj/dzwV8ZpVKpwQQH0QIRohvx0NgpKbw+fdTK+FVOfX09\nyy+/PADXXXcdAC+++CIAo0aNYrXVVmvw+mSSJMStqcalWvqSN1rh6M7s2bOBcizat28fJ05C7Jp6\nhKNjMZ+S8Xj88ceBqBGe8qlQKMTzaUhw/frXv45//sQTTwDlIwE9evRg4cKFAPHvucCvvOS17Jxz\nzgGiZvdp4cZ64cKF8cbf7373O6DcuHJpLvj144rFYqOHEoRjAfvttx+rrLIKUH5oxffffx83xk9f\nD41f8wsxKBQKdO/eHYBHHnkEgBNPPBGAyy67LI5NWA/V19fH33Ndkw/Ja1o4ghy+QuOGvr17947v\nPS699FKgeR4S46dEkiRJkiQpQ1Uc4VmcBQsWxFngsIOz/vrrx0d4Tj/9dKBcJht2bVR5oWlamzZt\neOihh4Dy41Hr6urMAudUmDJC5Ul43PSrr74aP0rsvPPOA+CUU06JG8sG7pjmR3g0+AUXXADAs88+\ny/Tp04GGu2jGLN/SxyO//PLLuPIkPM7v8MMPj5vrhd1uH5NaeaGBemiIF/7/vffei48gh6qTsWPH\nxtdIm+DnW9gBLRaL8TgL68+LL744bnb4+uuvA+WxaPVC82pqpzpUCoUjyaNHj2aLLbYAokakEB0L\n6du3L0Cj6mrlQ6jgC9WYgwYNio8th2M9LVu2dC7NsTAvzps3D4BZs2ax3nrrAeUG3I8//jj//Oc/\ngXKjbitQJEmSJEmScqBqK1CS2aVQeRIaB+2www5xBYqPg6uM9Mfqyy+/5H//93+BclVQ6GfTpk2b\n+HFwd999NxBl9M3m50cYbz/88AP33HMPQLz7kux78sYbbwDlBmuPPvpo/MhUmzdX1ldffQVEjbeS\nzbcg2hEFGDlyZJzJN17VI70DOmrUqPjx4eGxqvX19XHPm0022QQwxs0t/e/9/PPPc+yxxwIwefLk\nBj+DclVtuFb+/e9/Z5dddgFc21SLZE+TV199FYDu3bvz7rvvArDpppsCjsXmlq6++/jjj1l11VWB\nph9jO3XqVCCqcAd46aWX6NatG+BYrKT0uLn//vvjOTJUWgavv/46Xbp0AWDcuHFA1NjZ+OVfMs6h\nYjpUaI4YMSJ+lHhzxrLq7lDTk977778fdzH//e9/D8AJJ5xgSV2FpZtxXXHFFXECJTTjChPeggUL\n4sZ5lpTnS3oyGjp0KE8//TRQfmJSaOg8ffp0nnvuOQA6dOgAQNeuXV0YVlAyEXnRRRcB8O6778al\nyTNmzADgmmuuafAVXNBXsyFDhnDwwQcD5WORhUKB1VdfvcHrjG3zSo+pqVOnxjdmJ598MgDbbrtt\n/PpRo0Y1+P3kjZ3XyOoR4n7mmWcCUaPgkDhxrdr8isViPH7efvttAI4++mhuv/12AMaMGQOUn+Iy\nf/78eP0anoi18847e+wqB9Jz6sCBA3nyySeB8hOuwsbBddddx5FHHgmUn4hl0+Z8S9+DDBgwgJtv\nvhkobzqsueaaFUmCuXqSJEmSJEnKUHUp73Rlw9tvvx03BTrhhBOAqGGszWIrK72zedlll8WVJw8+\n+GCDnw0cODDOFJvRz5ewSxPi0qVLF+68806gXHo8c+ZMICoz33777QG47777Gv0NNb/a2to4dr/5\nzW8AOPjgg+Nyx9BoNBwjCDuk4BisJulYffPNN1x44YWAVX15EqoMQkz69OnDiiuuCMD5558PRI0O\nIYpXmGPD4zi32GILK8OqTG1tbbw7Go5/9O3b13FZQaVSKR4/oTnljBkz4qq9zz//vMHrV1111fjx\n1P379wcaVrGocsK1L8yL99xzT6P1TBh3p556KpdccglQnoOdR/MtHZ/u3bszevRoIKo8gcpVEfnJ\nkSRJkiRJylC1TWSb4s5M9XI3pnrMnz8fgAkTJgDEjxHffPPNadGiRcXel5bcxIkTAdhoo42Acgwl\nVVboiQGN+2KUSiWvkdJSMGXKlLiaNvSKCv2jWrVqFVeK2XC0ethfaNlW6ftGMw2SJEmSJEkZqr4C\npVgs2jejCpRKpThz31S20NhVh2KxuNgKrxDj8Bp3S/Njcdl6d9WWPZXendGSWdzYCzFM935TdUpe\nHx2X+bCk86TXyOpQKpUa9TdJzqOuTatbuBZC5U+bVH0CRVLzClNGeuqoqanxolQFkguMEC/jJlVW\nU0sxx6XUPJI3ZkFy/DkWq4+bCFqaPMIjSZIkSZKUwQoUSZIkSZKkDFagSJIkSZIkZTCBIkmSJEmS\nlMEEiiRJkiRJUgYTKJIkSZIkSRlMoEiSJEmSJGUwgSJJkiRJkpTBBIokSZIkSVIGEyiSJEmSJEkZ\nTKBIkiRJkiRlMIEiSZIkSZKUwQSKJEmSJElSBhMokiRJkiRJGUygSJIkSZIkZTCBIkmSJEmSlMEE\niiRJkiRJUgYTKJIkSZIkSRlMoEiSJEmSJGUwgSJJkiRJkpTBBIokSZIkSVIGEyiSJEmSJEkZTKBI\nkiRJkiRlMIEiSZIkSZKUwQSKJEmSJElSBhMokiRJkiRJGUygSJIkSZIkZTCBIkmSJEmSlMEEiiRJ\nkiRJUgYTKJIkSZIkSRlMoEiSJEmSJGUwgSJJkiRJkpTBBIokSZIkSVIGEyiSJEmSJEkZTKBIkiRJ\nkiRlMIEiSZIkSZKUwQSKJEmSJElShv8DxuWAI99b8eAAAAAASUVORK5CYII=\n",
            "text/plain": [
              "<Figure size 2000x400 with 40 Axes>"
            ]
          },
          "metadata": {
            "tags": []
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "## Example MNIST digits for one client\n",
        "figure = plt.figure(figsize=(20, 4))\n",
        "j = 0\n",
        "\n",
        "for example in example_dataset.take(40):\n",
        "  plt.subplot(4, 10, j+1)\n",
        "  plt.imshow(example['pixels'].numpy(), cmap='gray', aspect='equal')\n",
        "  plt.axis('off')\n",
        "  j += 1"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "c6wB6PggHO3g"
      },
      "source": [
        "이제 각 MNIST 숫자 레이블에 대한 각 클라이언트의 예제 수를 시각화해 보겠습니다. 페더레이션 환경에서 각 클라이언트의 예제 수는 사용자 동작에 따라 상당히 다를 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "vrjtRk5kICeN"
      },
      "outputs": [
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAsMAAAHOCAYAAAB9+gQBAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzt3Xt0VPW9//9XIFwTSAQmJJBAuAkh\ngFziQaoil5PUCwW5WEmJBoGmKloo3lI9R7FqibaoqO2pI4ixKBy1q0S5VQ0KVdF2BA5VaopCkACG\nBJKGEEIufL5/+CM/I+S+M3sn+/lYi7XMZOYzrwnzdr/Y2bN3gDHGCAAAAHChNnYHAAAAAOxCGQYA\nAIBrUYYBAADgWpRhAAAAuBZlGAAAAK5FGQYAAIBrUYYBF5swYYJWrlzp98c61enTp/WjH/1IISEh\nuuGGG+yOY5ulS5cqKSnJ8nWb+vPNzs5WQECAKioqJEnXXHON0tPTrY4JwGUow0ArEB0drXfffdfu\nGNX861//0g033KAePXooJCREI0aM0JNPPqnKyspmfd65c+fqv/7rvxr12DfeeEO5ubk6fvy4Xn/9\ndYuT1e2DDz7QD37wA4WEhKhbt266/PLL9fe//93vOZpLfX6+DXnfbN68WcnJyU3O9dJLL+mKK65o\n8joAWibKMADLffXVVxo7dqyioqL0j3/8Q//+97/1+uuvy+fz6eTJk3bHq9HBgwd18cUXKzAwsMGP\nPbe3srGKioo0ZcoU3XnnnTpx4oQOHz6shx56SB06dGjSuk5S18+3pb5vALRwBkCL17dvX/POO++c\nd/uJEyfMddddZ3r06GFCQ0PNddddZw4dOlT1/auuusqkpqaaSy+91HTt2tVMnTrVHD9+vOr7O3bs\nMOPGjTMhISFmxIgR5r333qv22BdeeOGCeebMmWOuvfbaWjNnZGSYoUOHmpCQEHPVVVeZvXv3Vn1P\nktm3b1/V18nJyeaBBx4wxhjz3nvvmd69e5vf/va3xuPxmPDwcPPiiy8aY4x5/vnnTWBgoGnXrp0J\nCgoyU6ZMMcYYk5aWZnr16mWCg4PNxRdfbN59993z8jz44IOmXbt2JjAw0AQFBZmVK1eayspK88gj\nj5g+ffoYj8djbrrpJlNYWGiMMebAgQNGklm5cqWJiooyV155ZYN//t/197//3YSEhNT48/ryyy/N\nxIkTTbdu3Uz37t3NT37yE1NQUFD1/b59+5onnnjCDB8+3HTu3NnMmzfPfPPNN+bqq682wcHBZvLk\nyebEiRPVsj///PMmIiLChIeHm9/+9rdVaz300ENmzpw5VV/X9j74vr1795qrrrrKhISEmKFDh5qM\njIwaf77fV9f75lzu8vJyY8z578FVq1aZIUOGmNDQUJOQkGCys7OrvifJ/M///I8ZOHCgCQ0NNbff\nfrs5e/as2bt3r+nQoYNp06aNCQoKqvo72Lhxo4mJiTHBwcGmV69e5je/+U2NuQC0bJRhoBWoqQzn\n5+ebN954w5w6dcoUFRWZWbNmmWnTplV9/6qrrjK9evUy//jHP0xxcbGZMWNGVQnKyckx3bp1Mxs3\nbjSVlZXm7bffNt26dTPHjh2remxNZbhnz55VBfVCsrKyTOfOnc3bb79tysrKzOOPP24GDBhgzpw5\nY4ypuwy3bdvW/Pd//7cpKyszGzduNJ06daoqet+9rzHGfPHFFyYyMtIcPnzYGPNtofryyy8vmOv7\nJXDVqlVmwIAB5quvvjInT54006dPN0lJSVXrSDI33XSTKS4uNiUlJQ3++X/Xv//9b9OtWzdz8803\nm02bNlW9nnP27dtn3n77bVNaWmqOHTtmrrzySrNo0aKq7/ft29eMHTvWfPPNNyYnJ8d4PB4zatQo\ns3PnTlNaWmomTpxoli5dWi377NmzTXFxsdmzZ4/p0aNH1Xvouz+Hut4H31VWVmYGDBhgHnvsMXPm\nzBmTmZlpgoODzRdffHHBn+/31fW+qa0M//nPfzYDBgwwe/fuNeXl5eaRRx4x48aNq3qsJHPdddeZ\ngoICc/DgQdOjRw+zefNmY4wxq1evNpdffnm15woPDzfbt283xnz7j5pPP/20xlwAWjYOkwBase7d\nu2vmzJnq3LmzunTpogceeEDbtm2rdp+bbrpJw4YNU1BQkB555BG99tprqqys1Jo1a3Tttdfq2muv\nVZs2bRQfH6+4uDht2rSpzuc9fvy4IiIiavz+//7v/+q6665TfHy82rVrp7vvvlunT5/WRx99VK/X\n1a5dOz344INq166drr32WgUHBysrK+uC923btq3OnDmjvXv3qry8XNHR0RowYEC9nueVV17RkiVL\n1L9/fwUHB2vZsmVat25dtUMili5dqqCgIHXq1Om8x9fn539O165d9cEHHyggIEA//elP5fF4NHXq\nVOXm5kqSBg4cqPj4eHXo0EEej0dLliw5b60777xTPXv2VO/evXXllVdq7NixGjVqlDp06KDp06dr\n165d1e7/0EMPKSgoSMOHD9ctt9yitWvXnperIe+Djz/+WMXFxUpNTVX79u01adIkTZky5YLrXkhd\n75vaPP/88/rlL3+pmJgYBQYG6v7779fu3bt18ODBqvukpqYqNDRUffr00cSJE7V79+4a12vXrp32\n7t2roqIiXXTRRRo9enSjcgFwPsow0IqVlJToZz/7mfr27auuXbtq/PjxKiwsrPZhpKioqKr/7tu3\nr8rLy5Wfn6+DBw/q9ddfV2hoaNWfDz74QEePHq3zebt3717r/Y4cOaK+fftWfd2mTRtFRUXp8OHD\n9Xpd3bt3r3bcaefOnVVcXHzB+w4cOFBPP/20li5dqrCwMM2ePVtHjhyp1/N8P2ffvn1VUVFRVVCl\n6j+/76vPz/+7YmJi9NJLLyknJ0efffaZjhw5osWLF0uSjh07ptmzZ6t3797q2rWrkpKSlJ+fX+3x\nPXv2rPrvTp06nff1939G3/+7v9DPpSHvgyNHjigqKkpt2vz/m5a+ffs26O+1Pu+vCzl48KAWLVpU\nlbFbt24yxlR77vDw8Kr/ru09I0l/+tOftGnTJvXt21dXXXWVduzY0ahcAJyPMgy0YsuXL1dWVpY+\n+eQTFRUVafv27ZIkY0zVfQ4dOlT1319//bXatWunHj16KCoqSjfddJMKCwur/pw6dUqpqal1Pu9/\n/ud/6k9/+lON3+/Vq1e1PXbGGB06dEi9e/eW9G1RKSkpqfr+N998U+/XHBAQcN5tP/nJT/TBBx/o\n4MGDCggI0H333Vevtb6f8+uvv1ZgYGC1knmh5zunPj//mgwZMkRz587VZ599Jkn65S9/qYCAAO3Z\ns0dFRUVas2ZNvdapzff/7nv16nXefRryPujVq5cOHTqks2fPVlv33N9rXep639QmKipKzz//fLWc\np0+f1g9+8IM6H3uhv8NLL71UGRkZOnbsmK6//nr9+Mc/blQuAM5HGQZaifLycpWWllb9qaio0MmT\nJ9WpUyeFhobqxIkTevjhh8973Jo1a7R3716VlJTowQcf1KxZs9S2bVslJSXprbfe0l/+8hdVVlaq\ntLRU77//vnJycurM8vDDD+ujjz7SPffcU1Vkv/zySyUlJamwsFA//vGPtXHjRmVmZqq8vFzLly9X\nhw4dqorLyJEj9eqrr6qyslJbtmyp8dCCC+nZs6f2799f9XVWVpa2bt2qM2fOqGPHjurUqZPatm1b\nr7USExP11FNP6cCBAyouLtb999+vG2+8sd5nm6jPz/+cL774QsuXL6/6+R46dEhr167VZZddVrVW\ncHCwQkNDdfjwYf3mN7+pV4baPPLIIyopKdHnn3+u1atX68YbbzzvPg15H4wdO1ZBQUF64oknVF5e\nrvfff19vvfWWZs+eXa88db1vanPrrbdq2bJl+vzzzyWp6kwU9dGzZ0/l5OSorKxMklRWVqZXXnlF\n//73v9WuXTt17dq13u8ZAC0PZRhoJa699lp16tSp6s/SpUu1ePFinT59Wj169NBll12mq6+++rzH\n3XTTTZo7d67Cw8NVWlqqZ555RtK3e9oyMjL061//Wh6PR1FRUfrNb35Tba9fTQYMGKAdO3YoOztb\nsbGxCgkJ0cyZMxUXF6cuXbpo8ODBWrNmje6880716NFDb731lt566y21b99ekrRixQq99dZbCg0N\n1SuvvKLrr7++3j+H+fPna+/evQoNDdX111+vM2fOKDU1VT169FB4eLiOHTumX//61/Vaa968ebrp\npps0fvx49evXTx07dtSzzz5b7yz1+fmf06VLF33yySdVhfKyyy7TsGHDtHz5cknfHt+7c+dOhYSE\n6LrrrtOMGTPqnaMmV111lQYOHKjJkyfr7rvvVkJCwnn3acj7oH379nrzzTe1efNm9ejRQ7fffrte\nfvllDRkypF556nrf1Gb69Om67777NHv2bHXt2lXDhg3T5s2b6/W8kyZNUmxsrMLDw9WjRw9J0h//\n+EdFR0era9eu+sMf/qA1a9bUay0ALU+Aaerv2QAALUp2drb69eun8vLyRp1TGQBaE/YMAwAAwLUo\nwwAAAHAtDpMAAACAa7FnGAAAAK5FGQYAAIBrUYYBAADgWpRhAAAAuBZlGAAAAK5FGQYAAIBrUYYB\nAADgWpRhAAAAuBZlGAAAAK5FGQYAAIBrUYYBAADgWpRhAAAAuBZlGAAAAK5FGQYAAIBrUYYBAADg\nWpRhAAAAuBZlGAAAAK5FGQYAAIBrUYYBAADgWpRhAAAAuBZlGAAAAK5FGW7Bli5dqqSkJEnS119/\nreDgYFVWVtqcCkBNmFmg5WBe3YMy7HCvvvqq4uLiFBwcrIiICF1zzTX64IMPzrtfnz59VFxcrLZt\n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\ntCSpS5cuiomJ0eHDh23LI317jsmNGzdqwQJrrtzSFEVFRdq+fbvmz58vSWrfvr1CQ0NtzVRRUaHT\np0+roqJCJSUlfj8f5/jx49WtW7dqt2VkZCg5OVmSlJycrPXr1/s1U3NiZmvHvNaOefUv5rV2TppX\nyXkz64Z5dUQZvtBlJ+0un+dkZ2dr165dGjt2rK05Fi9erCeeeEJt2tj/V7Z//355PB7dcsstGjVq\nlBYsWKBTp07Zlqd37966++671adPH0VERCgkJEQJCQm25TknNzdXERERkr79n/+xY8dsTmQdZrZ2\nzGvNmFf/Y15r56R5lZw1s26ZV0f8zZt6XnbS34qLizVz5kw9/fTT6tq1q205NmzYoLCwMMec36+i\nokI7d+7Ubbfdpl27dikoKMjWY9AKCgqUkZGhAwcO6MiRIzp16pTWrFljWx43YGZrxrzWjnn1P+a1\nZk6bV8lZM+uWeXVEGXbiZSfLy8s1c+ZMzZkzRzNmzLA1y4cffqg333xT0dHRmj17trZu3aqkpCTb\n8kRGRioyMrLqX/KzZs3Szp07bcvz7rvvql+/fvJ4PGrXrp1mzJihjz76yLY85/Ts2VNHjx6VJB09\nelRhYWE2J7IOM1sz5rV2zKv/Ma81c9q8Ss6aWbfMqyPKsNMuO2mM0fz58xUTE6MlS5bYluOcZcuW\nKScnR9nZ2Vq3bp0mTZpk67/MwsPDFRUVpaysLElSZmamhg4daluePn366OOPP1ZJSYmMMcrMzFRM\nTIxtec6ZOnWq0tPTJUnp6emaNm2azYmsw8zWjHmtHfPqf8xrzZw2r5KzZtY189qkj99ZaOPGjWbQ\noEGmf//+5tFHH7U1y1//+lcjyQwfPtxccskl5pJLLjEbN260NdM57733niM+7bpr1y4zZswYM3z4\ncDNt2jRz4sQJW/M8+OCDZvDgwSY2NtYkJSWZ0tJSvz7/7NmzTXh4uAkMDDS9e/c2K1euNPn5+WbS\npElm4MCBZtKkSeb48eN+zdTcmNm6Ma8Xxrz6H/NaN6fMqzHOmlk3zCuXYwYAAIBrOeIwCQAAAMAO\nlGEAAAC4FmW4BVu6dGnVp16//vprBQcHq7Ky0uZUAGrCzAItB/PqHpRhh3v11VcVFxen4OBgRURE\n6JprrtEHH3xw3v369Omj4uJitW3btsnPOWHCBK1cubLG7+fn5+vyyy9X9+7dFRoaqnHjxunDDz9s\n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\n4UrNAAAAAElFTkSuQmCC\n",
            "text/plain": [
              "<Figure size 1200x700 with 6 Axes>"
            ]
          },
          "metadata": {
            "tags": []
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Number of examples per layer for a sample of clients\n",
        "f = plt.figure(figsize=(12, 7))\n",
        "f.suptitle('Label Counts for a Sample of Clients')\n",
        "for i in range(6):\n",
        "  client_dataset = emnist_train.create_tf_dataset_for_client(\n",
        "      emnist_train.client_ids[i])\n",
        "  plot_data = collections.defaultdict(list)\n",
        "  for example in client_dataset:\n",
        "    # Append counts individually per label to make plots\n",
        "    # more colorful instead of one color per plot.\n",
        "    label = example['label'].numpy()\n",
        "    plot_data[label].append(label)\n",
        "  plt.subplot(2, 3, i+1)\n",
        "  plt.title('Client {}'.format(i))\n",
        "  for j in range(10):\n",
        "    plt.hist(\n",
        "        plot_data[j],\n",
        "        density=False,\n",
        "        bins=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "B9vBNGd2I4Kn"
      },
      "source": [
        "이제 각 MNIST 레이블에 대한 클라이언트별 평균 이미지를 시각화해 보겠습니다. 이 코드는 하나의 레이블에 대한 사용자의 모든 예제에 대한 각 픽셀 값의 평균을 생성합니다. 한 고객의 숫자에 대한 평균 이미지는 각 개인의 고유한 필기 스타일로 인해 같은 숫자에 대한 다른 고객의 평균 이미지와 다르게 보일 것입니다. 해당 로컬 라운드에서 해당 사용자의 고유 한 데이터에서 학습하므로 각 로컬 훈련 라운드가 각 클라이언트에서 다른 방향으로 모델을 어떻게 움직일지 뮤즈할 수 있습니다. 튜토리얼의 뒷부분에서 모든 클라이언트의 모델에 대한 각 업데이트를 가져와서 각 클라이언트의 고유한 데이터에서 학습한 새로운 글로벌 모델로 통합하는 방법을 살펴보겠습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qfkNoBCTJ5Pl"
      },
      "outputs": [
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAr8AAAFPCAYAAABEY6ZqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzt3Xl8VPW9//HPzCSZrGQhZIOwCwgP\nQEAqoAi1gqWsgmvZrqJeioqCVBStRtvS60Wx5YfWpS5QRES4F4GKIlosWi8qiwgFAdkDZAEmK0km\nmbl/+HMun3MCkyjZ5vt6Ph4+Hnwm58w5znxz5s3w+X6Pw+/3+wUAAAAwgLOhTwAAAACoL4RfAAAA\nGIPwCwAAAGMQfgEAAGAMwi8AAACMQfgFAACAMQi/ACQrK0smTJggIiJHjhyR2NhYqaqqauCzAmpu\n48aN0qpVq3rfF0DTQ/gFDLF06VK5/PLLJTY2VtLT02XYsGHyySef2LZr3bq1FBcXi8vl+tHHHDx4\nsPzlL3+p0bbFxcWSmZkpIiKvvvqqzJw5U/18+/bt0qdPH4mOjpY+ffrI9u3bAz/LysqSrKysWp+f\nw+GQ1NRUqaysDDxWWVkpKSkp4nA4av18P9brr78uV111Vb0ft7YGDx4skZGREhsbK8nJyTJ27Fg5\nceLERXnupvIaAGi6CL+AAebPny/333+/zJkzR3JycuTIkSMybdo0eeeddxr61AK2bdsmvXr1EhGR\nLVu2SO/evQM/q6iokNGjR8uECRPkzJkzMnnyZBk9erRUVFT86OMmJCTIunXrAvW7774riYmJP/p5\nQ93ChQuluLhY9u7dKx6PR2bMmFHr5zj3Lx0AUF8Iv0CIKygokMcee0yee+45GTt2rMTExEh4eLiM\nHDlS5s2bZ9v+0KFD4nA4AsGkoKBApkyZIunp6dKyZUt59NFHAy0R339LN2vWLElMTJR27doFguQj\njzwimzZtknvuuUdiY2PlnnvuueB5fvnll9KnT5/An88Nvxs3bpTKykq5//77xe12y/Tp08Xv98tH\nH31ke578/HwZMWKEJCQkSFJSkgwcOFB8Pt95jztx4kRZvHhxoF68eLFMmjTJ9hqe7zX49ttv5Zpr\nrpHmzZtLcnKyjB8/XjweT2Dftm3bytNPPy09evSQ+Ph4ufnmm6WsrOyCr8W5+86bN0969OghMTEx\nMmXKFMnJyZFhw4ZJXFycXHvttXLmzJnA9jfeeKOkpaVJfHy8XH311bJr167Az06dOiUjR46UZs2a\nSd++feXRRx9V37Du2bNHhgwZIklJSdK5c2dZvnx5jc4xKSlJxo0bJzt37hQRkfLycpk1a5a0bt1a\nUlNTZerUqXL27FkR+b/2gqeeekrS0tLktttuq9Exvvfaa6/JpZdeKnFxcdK+fXt58cUXbdvMnTtX\nkpOTpW3btvLGG28EHr/QeQEwC+EXCHGfffaZlJWVyfXXX/+D9p88ebKEhYXJ/v37Zdu2bbJ+/XrV\nyrB582bp3Lmz5Ofny4MPPihTpkwRv98vv//972XgwIGBbwgXLlxY7fNPmTJFEhISZPbs2TJv3jxJ\nSEiQL7/8UgYMGCDdunUTEZFdu3ZJjx49VCtCjx49AuHu3LaHZ555Rlq1aiV5eXmSk5Mjc+fOvWAL\nw5gxY+Qf//iHeDwe8Xg8smnTJhk9enSNXwO/3y8PP/ywHD9+XHbv3i1Hjx61tWAsX75c3nvvPTl4\n8KDs2LFDXn/99Rq99iIiK1eulA8++ED27t0ra9askWHDhsncuXMlPz9ffD6fLFiwILDtsGHDZN++\nfZKbmyu9e/eW8ePHB3529913S0xMjJw8eVIWLVokixYtCvyspKREhgwZIr/85S8lNzdX3nzzTZk2\nbZoKz+eTn58vK1euDHxrP3v2bNm7d69s375d9u/fL9nZ2fLkk08Gtj958qScPn1aDh8+LC+99FKN\nXwcRkZSUFFm7dq0UFhbKa6+9JjNmzJCtW7eq587Pz5fs7GxZtGiR3HXXXfLNN9/U6LwAmIPwC4S4\nU6dOSXJysoSFhdV635ycHFm3bp388Y9/lJiYGElJSZEZM2bIsmXLAtu0adNG7rzzTnG5XDJ58mQ5\nceKE5OTk1PgYr7zyihw8eFDatm0r+fn58vzzz8vUqVPF4/EEwldxcbHEx8er/eLj46WoqMj2fOHh\n4XLixAk5fPiwhIeHy8CBAy8YfiMjI2XkyJHy1ltvybJly2TUqFESGRlZ49egY8eOMmTIEHG73dKi\nRQuZOXOmfPzxx+oY06dPl4yMDElKSpKRI0eqfuVg7r33XklNTZWWLVvKwIED5YorrpBevXqJ2+2W\n66+/XrZt2xbY9vbbb5e4uDhxu92SlZUlX331lRQUFEhVVZWsXLlSnnjiCYmOjpauXbvK5MmTA/ut\nXbtW2rZtK7fddpuEhYVJ7969Zdy4cbJixYrzntf06dMlISFBevbsKenp6TJ//nzx+/3y8ssvy7PP\nPitJSUkSFxcnc+bMUePF6XTKE088IW63W6Kiomr8OoiIDB8+XDp06CAOh0MGDRokQ4cOlU2bNqlt\nfvvb34rb7ZZBgwbJ8OHDZfny5TU6LwDmqP2nIYAmpXnz5pKfny+VlZW1DsCHDx8Wr9cr6enpgcd8\nPl9gYpqISFpaWuDP0dHRIvJdWK2J1atXy6RJk8Tr9UplZaWkpaVJSUmJREZGyhtvvCEbNmwITNIr\nLCxU+xYWFkpcXJztOX/9619LVlaWDB06VERE7rrrLnnooYcueB6TJk2Shx9+WPx+vzz11FO1eg1y\nc3Nl+vTpsmnTJikqKhKfz2frGba+RsePH6/Bq/Od1NTUwJ+joqJs9fevdVVVlTzyyCPy9ttvS15e\nnjid3323kZ+fL2fPnpXKykr1vp3758OHD8vmzZslISEh8FhlZaVMnDjxvOe1YMECueOOO9Rjubm5\nUlpaGmhfEfnum/FzVw5p0aKF+stFbaxbt06eeOIJ2bt3r/h8PiktLZXu3bsHfp6YmCgxMTGBuk2b\nNnL8+HHJy8sLel4AzME3v0CI69+/v0RGRsqqVatqvW9mZqa43W7Jz88PtAUUFhbW6J/DRSToigmj\nRo0Sj8cjEydOlNdff108Ho8kJSVJXl6eeDweufzyy0VEpFu3brJjxw7x+/2BfXfs2BFoizhXXFyc\nPPPMM3LgwAFZs2aNzJ8/Xz788MMLnsfAgQMD31hbVxoI9ho8/PDD4nA4ZMeOHVJYWChLlixR51lf\nli5dKu+8845s2LBBCgoK5NChQyLyXchr0aKFhIWFybFjxwLbHz16NPDnzMxMGTRoUOD/z+PxSHFx\nsfz5z3+u1TkkJydLVFSU7Nq1K/A8BQUF6i9DP3QVjfLychk3bpzMmjVLcnJyxOPxyC9+8Qv1Wp85\nc0ZKSkoC9ZEjRyQjI6NG5wXAHIRfIMTFx8fLk08+KXfffbesWrVKSktLxev1yrp16+TBBx+84L7p\n6ekydOhQeeCBB6SwsFB8Pp98++23tn/WP5/U1FQ5cOBA0O2+X93h4MGDkp6ebvtmcPDgweJyuWTB\nggVSXl4e6B++5pprbM+1du1a2b9/v/j9fmnWrJm4XK6gy7Y5HA5Zs2aNrF692hbOgr0GRUVFEhsb\nKwkJCZKdnV3tJML6UFRUJG63W5o3by6lpaUyZ86cwM9cLpeMHTtWsrKypLS0VPbs2aMm+Y0YMUL2\n7t0rf/3rX8Xr9YrX65UvvvhCdu/eXatzcDqdcuedd8qMGTMkNzdXRESys7Pl/fffr9Xz+P1+KSsr\nU/9VVFRIeXl5IMivW7dO1q9fb9v38ccfl4qKCtm0aZOsXbtWbrzxxot2XgBCA+EXMMDMmTNl/vz5\n8rvf/U5atGghmZmZsnDhQhkzZkzQfRcvXiwVFRXStWtXSUxMlBtuuKHGa7red999smLFCklMTJTp\n06dXu43X65VDhw5Jp06dZOvWreqfpr8XEREhq1atksWLF0tCQoK8+uqrsmrVKomIiLBtu2/fPrn2\n2mslNjZW+vfvL9OmTZPBgwcHPddu3bpV+02yyIVfg8cff1y2bt0q8fHxMnz4cBk7dmzQY9WFSZMm\nSZs2baRly5bStWtX6devn/r5woULpaCgQNLS0mTixIly6623itvtFpHvvi1fv369LFu2TDIyMiQt\nLU1mz54t5eXltT6Pp556Sjp27Cj9+vWTZs2aybXXXhuYdFZT//znPyUqKsr234IFC+Smm26SxMRE\nWbp0qYwaNUrtl5aWJomJiZKRkSHjx4+XF154Qbp06XLRzgtAaHD4G+Lf5wAADWr27NmBlR8AwCR8\n8wsABtizZ0+gb/rzzz+XV1555QcvfwcATRmrPQCAAYqKiuTWW2+V48ePS0pKijzwwAO29YwBwAS0\nPQAAAMAYtD0AAADAGIRfAAAAGIPwCwAAAGMQfgEAAGAMwi8AAACMQfgFAACAMQi/AAAAMAbhFwAA\nAMYg/AIAAMAYhF8AAAAYg/ALAAAAYxB+AQAAYAzCLwAAAIxB+AUAAIAxCL8AAAAwBuEXAAAAxiD8\nAgAAwBiEXwAAABiD8AsAAABjEH4BAABgDMIvAAAAjEH4BQAAgDEIvwAAADAG4RcAAADGIPwCAADA\nGIRfAAAAGCOsPg/mO3lJfR4OdcyZtq9OnpdxElrqapyIMFZCDWMFNcXnD2rifOOEb34BAABgDMIv\nAAAAjEH4BQAAgDEIvwAAADAG4RcAAADGIPwCAADAGIRfAAAAGIPwCwAAAGMQfgEAAGAMwi8AAACM\nQfgFAACAMQi/AAAAMAbhFwAAAMYg/AIAAMAYhF8AAAAYg/ALAAAAYxB+AQAAYAzCLwAAAIxB+AUA\nAIAxCL8AAAAwBuEXAAAAxiD8AgAAwBiEXwAAABiD8AsAAABjhDX0CQAAAKDxqvL7gm7jcjSd71Ob\nzpkCAAAAPxLhFwAAAMYg/AIAAMAY9PwCABAigvVmNqW+TNSfAt9ZVUc6dDws9Xlt+yS6ouv0nOoS\nvwUAAAAwBuEXAAAAxiD8AgAAwBj0/NYBr79K1U5xqJqeK4jQm2cy63tfKVXn2fI7Tsv3FFxTzGEd\nKz7xq7q2Y8H6fIwdM5T7dc/ux2d1v+7OsvaqLqqK1Pv77HExJaJQ1W0j8lU9IDJHb++KqdnJ1gNG\nPQAAAIxB+AUAAIAxCL8AAAAwBj2/P0Cwnimf6J+HO8Lr/JzQ+Fh7v4t95aous4yjw5VRqu7j1vuH\nO1wX8ezQkKzXDFeQ7yGsY8naIxxsfzRdtp5cy3Uju6pU1Qe8zVTt8enezp4RJ1XdOsy+Vit9wI1b\ndfNFrO/Zo7ndVX1p1HHLc+he8a2FrVX92YF2qvYV2nOMO09HyN/c8paq450Rtn0aC0Y4AAAAjEH4\nBQAAgDEIvwAAADAGPb81EKzH9zlPpq7/NUjVQ9vtUfXvUj9RdaxTr6eH0OS1rM85P3+gqt9d0V/V\nd45/V9X3Jx6yPSdrdjY8az/uiaqzqt5enmLb5/OSDqpen91F1af2NVe1M6VM1cM771T17BYbVZ0e\nFnv+E0ajlV9VYntsdvZ1qt60Ufdytlmrx1vEwVxVV7TT4y97sO7xvWb0Ftsx/5Tx2QXPk+tM3bJe\nU6zziNzVzCN6o0hfM/77Lf358uk12aqOi9BzUA6eTlJ1i6QiVZd8Zb+O9bvhK1XfEpunalcjnu/E\nCAYAAIAxCL8AAAAwBuEXAAAAxiD8AgAAwBhMeLOobvHocn+lqkfvGac3yEpWZeambar++J4Bql4y\n7YSqp8QfsR3TKXoBaiYYND35lolPL535iap3Tuqs6qh+ekJcV7eeoGCdBCHCjS8ag4OVejLamx79\nPi/6h554IiLS5fnTqk7cvU/V8VfFqNpVrt/7j/vqY6T/qkDVs5K+ucAZ///n5JrS6ByotN8U4O97\n9HXC+qG9f7zeJyJJfx45d+sJbq026JtibOjRyX4iQSa8oW4Fm+C2usR+Y5L/fP5mVUeW6c+T0r9m\nqPp0c50xBtxqyS3vXabq8nY6B4mIvJz5qaqr/LZNGi2ufgAAADAG4RcAAADGIPwCAADAGMb3/Fp7\nfH1ib1p58ITu2Tv7vO6difLrxaJPTdE3K4g/4FX1zpJWqvY2O2g7ptth/FvT5JT79fv8jbeZql/f\nfKWqO+38QtWDFum/iw6N1s9X5dc9WmicUsN1/+0tV9n7J0/0jbc8EqeqL09U6J8u02OpzLLe/BXR\n36q6uuuYdR4BGp+fuO03Bdg35GVVW+egbDiboOqZn+vez8T9+jMu/zLdLzqz+6panyfqVpjouRzH\nKotVfd/f77Ttk3FCv8+eDvrzJP6g/nlhZz2PYP1WffOUzmv0MSOf1jdPEal+jlRTwTe/AAAAMAbh\nFwAAAMYg/AIAAMAYNJZafFpm77l6d7Ne7y4+VffjdJut19RsEaF7Zd7/01WqPlSS9GNOEY1Adb1O\nTsvfJXeVt1R11yePqzpvsu4Nfyx1vqq9fr1+J2v6Nk6dwvWavO0s63bv9e637fN+cTdVv7zi56rO\n/ECvxXpgrN7/lp9tUnX/SD3vINxhv46h8anJnJPdXt37f/2q+1Xd5U963fgOB/V6rWUj9JrQ9/7m\nbVXfFGvv5RTWmW9Q1r7ux4/r60PqP+yfBTHH9Lry8dt1DhGXfg+rwvV60Al/1XMTDj+m70+ws+Mi\n2zHP+PQxk10xtm0aK0Y0AAAAjEH4BQAAgDEIvwAAADCGcT2/wXqsXs3V/bkiItHHdH9NQVe9Pt6L\nrXSvzE0Hfqbq8FJ9jD6JuieQNX0bP+u4OeuvsG1T5NN9WgtWjlB1u5wtqu45zaPqSMs4sK4bTM9v\n4+T16+vBFt1+K0tODbbts/0/9DyCqBb6GpEy75Cq/z15q+WYeiw8d6azqrtGZtuO2TPilKrTw2Jt\n26B+WXs7q/sdDxd97bmir55jEvdWmarXf9VX1Smb9HPuKtVzEZyxeTU7WdQb6zjoEqv7uv/eT88Z\nEBGpitDrNyd/ri9ERV302uIOn77m5P+7noPyuwlLgp5nvDMy6DaNFd/8AgAAwBiEXwAAABiD8AsA\nAABjGN9s6rP0UxV73fZtLK9S5Endj9Pxzam6Xlai6lOz9Jqdc5K3W87B/ncQ+jsbt+ren6fz9LqI\nHZboXrrDsy5X9Vstn1F1laWP07puMBoHa/93sU/31r2Wr3v+j45Ptz1Hs9P7VJ03U/fs7nnlUlW/\n9HWmql1n9DWmtGNzVb8w2dJ4LCIv9dU9fCku3W/KWq71b6dXr6f7dVlL2zbNw/R6rVmt1qr6ZJVe\n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\nMIZxPb/W3s0UV5GqvzrQyrZPlz/rdRRP/DRJ1Z3656i6wq/X3C21rN3ocuh+0bBq1ui19hHS49uw\nrD2+p3z2nqv0X3tVffK23qouK9Njbdbtv1J1Tl+9tuYDt69Q9b810+u0itAL3hQMjfbaHvtZLz0v\nwPq+/fqknnuweU97VTvP6u3qKPL9AAAG/0lEQVSdafoa88Klb9iOGXytcDS0cIf9s+DRlI9VvcGj\n140O+3CLqg89MkDVz9/+gqqvjNTjMZz+3kYn2HV8UNQp22M/vUXfL2DNVz31Bl79nGmf6s+Okz8J\nV/XUxM2qdjt073hNzrMxa7pnDgAAANQS4RcAAADGIPwCAADAGMb1/Fp7qrpG6D7MhQPtvXKzDt2u\n6oxPylW9873Oqr7/snRVL+3ziqovc9Nj1dgFW9f3jgPjbPtU7f1W1WU3p6o688Zdqi666QpVR+X6\nVf37rb9Q9cRBr9qO6RO9j71jEA3N2pctYn/fnj+j14BeuUP3i4tPjz9fpH7OOb30Gr7dI3T/XnXn\n0ZT79UKF9T0p99v7w/t+cJ+q23ytt6n6qWVuQWfd/93Cpddz9dk+9rlqNDXxTnv/7bPpukf30dSN\nqr7ifT2Owo7oOSSPj1+r6mSXPkZ1a9s3ZVz9AAAAYAzCLwAAAIxB+AUAAIAxQr7n19pD9VaR7sdd\ndGyUqt/pstz2HEv+7Y+q/s3gMao+u7+lqp1HYlWde5muRSw9W9X0BNKP17hYezT3/LOdbZtL0vQ2\nKV/q9znn3v6qLtfLRdvuxd4y2XPBcxAJvT6sUFTd7/KHpbond/5nQ/Q+0ZWqrirTfZmTBnyq6lvj\njliOYL+0c01peNa5BNY5KD//+pe2fTJX6/et4K5CVRfvTlS167je/2SV/vzpEm7vK0bTYh1HIiI+\n0TliSUF3VXe640tVf7P0MlXfEndG1eWWXBLusM8jaMq4GgIAAMAYhF8AAAAYg/ALAAAAY4Rcz6+1\nF2Zdqe6HmvvWTaqO0O1T0v3IPbbnjDiue13iDuufR6XpvkvHZQWq7u3WvZsiMaqiF6/xK/DptTP9\n1bTa+tKaq9r9/lZVp67TY9M3sJeqD9yln29V5yWqdkq07ZiMncbvTFWp7bF7t0xVdVyyXou1+Ggz\nVU8d/JGqR8TtULXb4VY146Jxsvbon6gsVnXFMr02uIiIRy8HLvEu3YvpPmNZA7qv/lDrbv2QE/sa\nsWj6CnwVql539yBVn71B319gy9V6LlO5X8dBd4j1+FpxhQQAAIAxCL8AAAAwBuEXAAAAxgi5nl/r\nuomdw/X9qxN/kqNq35spqs585JjtOf0Jcao+OrKFqlMG6oUVn+v0pqqTXbrHF42ftTcv3hmp6v6D\ndtn22XWwm6pTS9qouqyN7j/3PXhK1Z9d+oaqU1zW9aHRFL1VdIntses67FZ1mqUv81hLPVaGxX2t\n6lRL3yc9vo1TdWu4n+t4le7DdNiXb5WOS06ruqR9gqrzR+h1e5/tuUrVzZ26x5ex0vRY5zJVt777\nlUtnqfqSr/6l6ru/2KLqaIcee6atGc9vAQAAAIxB+AUAAIAxCL8AAAAwBuEXAAAAxnD4/X5/fR3M\nd9I+8aO+lVoWgj5WpScLuMT+ckRb+sCTXXoCgXWSnSmcafvq5HkbwzgJptzvtT32WZm+0UCJX08o\n6B2Rr+r0MD2hzTo5JlQmptTVOBFpGmMlt6rE9ph1ElK5v1LVPtFjIdYy4TJUmTZWrL/zfzjV1bbN\nq1uvVPVVnfVr9ETGu6puF27GRFmTP3+2lFfYHrvl7ftUfd1P9U2WFrbcrGrrJLpQzTHnGyeh8ekK\nAAAA1ADhFwAAAMYg/AIAAMAYxvX8WtWkzzLYQuVWodKrGYzJPVfVCTZOfJZ+cuui4qE6bkzr48QP\nx1ipvVCdKxCMyZ8/RyqLbY8drYxW9ZWRZoyDYOj5BQAAgPEIvwAAADAG4RcAAADGCGvoE2ho1v6o\n6vo2TemhQt0K1XUUAVwc1X3+VIpej9Vp+c6K64p5WofZ13Ju6dJjx9Re8Jri1QAAAIAxCL8AAAAw\nBuEXAAAAxjC+59eKvhj8UIwdAD9GddcQF99R4Qfg8+jCeHUAAABgDMIvAAAAjEH4BQAAgDHo+QUA\nAGjC6PGtHV4tAAAAGIPwCwAAAGMQfgEAAGAMwi8AAACMQfgFAACAMQi/AAAAMAbhFwAAAMYg/AIA\nAMAYhF8AAAAYg/ALAAAAYxB+AQAAYAzCLwAAAIxB+AUAAIAxCL8AAAAwBuEXAAAAxiD8AgAAwBiE\nXwAAABiD8AsAAABjEH4BAABgDMIvAAAAjEH4BQAAgDEIvwAAADAG4RcAAADGIPwCAADAGA6/3+9v\n6JMAAAAA6gPf/AIAAMAYhF8AAAAYg/ALAAAAYxB+AQAAYAzCLwAAAIxB+AUAAIAxCL8AAAAwBuEX\nAAAAxiD8AgAAwBiEXwAAABiD8AsAAABjEH4BAABgDMIvAAAAjEH4BQAAgDEIvwAAADAG4RcAAADG\nIPwCAADAGIRfAAAAGIPwCwAAAGMQfgEAAGAMwi8AAACMQfgFAACAMQi/AAAAMMb/Aqlhs+CNz7Ex\nAAAAAElFTkSuQmCC\n",
            "text/plain": [
              "<Figure size 1200x500 with 10 Axes>"
            ]
          },
          "metadata": {
            "tags": []
          },
          "output_type": "display_data"
        },
        {
          "data": {
            "image/png": "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\n",
            "text/plain": [
              "<Figure size 1200x500 with 10 Axes>"
            ]
          },
          "metadata": {
            "tags": []
          },
          "output_type": "display_data"
        },
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAr8AAAFPCAYAAABEY6ZqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzt3Xl8VfWd//HPvcnNRvYESAIBZAcF\nBXcWoYpYqqJisaNU2g5WLfbX1qUyLq3ozDhjba1lmKnWWhTXuoxrS6FaEayOGyiKsu8EEgJZyXZz\n7/n90UdT3+dEQpQlyff1fDz6ePhOzr3ncM/3nvOBfr7fE/I8zzMAAADAAeGjfQAAAADAkULxCwAA\nAGdQ/AIAAMAZFL8AAABwBsUvAAAAnEHxCwAAAGdQ/AKwuXPn2je/+U0zM9u2bZulp6dbLBY7ykcF\nHLylS5da7969j/hrAXQ+FL+AIx5//HE76aSTLD093QoLC23KlCn2xhtvBLbr06eP1dbWWkJCwpfe\n58SJE+23v/3tQW1bW1trxcXFZmb2u9/9zq677rqW361bt84uuOAC6969u+Xm5to555xja9eubfn9\n3Llzbe7cue0+vlAoZD179rTm5uaWnzU3N1uPHj0sFAq1+/2+rIceesjGjRt3xPfbXhMnTrSUlBRL\nT0+3/Px8mzZtmu3ateuQvHdn+QwAdF4Uv4AD7rnnHvvRj35kN998s5WWltq2bdts9uzZ9sILLxzt\nQ2uxcuVKGzVqlJmZvf/++zZ69OiW31VWVtrUqVNt7dq1VlpaaqeccopdcMEFh2S/2dnZtmjRopb8\nxz/+0XJycg7Je3dl8+fPt9raWlu3bp1VVlbatdde2+73+OxfOgDgSKH4Bbq4qqoq++lPf2r//d//\nbdOmTbNu3bpZJBKx888/3+6+++7A9lu2bLFQKNRSmFRVVdmsWbOssLDQevXqZbfeemtLS8Tf/5Xu\nhhtusJycHDvmmGNaCslbbrnFli9fbt///vctPT3dvv/97x/wON977z078cQTW/77s8XvKaecYrNm\nzbLc3FyLRCJ27bXX2tq1a23v3r2B9ykvL7fzzjvPsrOzLTc318aPH2/xePxz93v55ZfbwoULW/LC\nhQtt5syZgc/w8z6DjRs32plnnml5eXmWn59vM2bMsMrKypbX9uvXz37+85/byJEjLSsry77xjW9Y\nQ0PDAT+Lz7727rvvtpEjR1q3bt1s1qxZVlpaalOmTLGMjAybNGmSVVRUtGw/ffp0KygosKysLDvj\njDNs9erVLb/bu3evnX/++ZaZmWknn3yy3XrrrfIvrGvWrLGzzz7bcnNzbciQIfbUU08d1DHm5uba\nxRdfbB9//LGZmTU2NtoNN9xgffr0sZ49e9rVV19t9fX1ZvaP9oK77rrLCgoK7Dvf+c5B7ePvFixY\nYMOGDbOMjAzr37+/3X///YFt7rzzTsvPz7d+/frZY4891vLzAx0XALdQ/AJd3FtvvWUNDQ120UUX\nfaHXf+tb37LExETbsGGDrVy50pYsWSKtDG+//bYNGTLEysvL7cYbb7RZs2aZ53n27//+7zZ+/PiW\nfyGcP39+q+8/a9Ysy87Otjlz5tjdd99t2dnZ9t5779mYMWPs2GOPbfU1y5Yts4KCAsvLyzMzbXv4\nxS9+Yb1797Y9e/ZYaWmp3XnnnQdsYbjwwgtt2bJlVllZaZWVlbZ8+fLAvyof6DPwPM9uuukmKykp\nsU8//dS2b98eaMF46qmn7E9/+pNt3rzZVq1aZQ899NCBPnLx7LPP2p///Gdbt26dvfTSSzZlyhS7\n8847rby83OLxuM2bN69l2ylTptj69eutrKzMRo8ebTNmzGj53TXXXGPdunWz3bt328MPP2wPP/xw\ny+/2799vZ599tl122WVWVlZmTzzxhM2ePVuK589TXl5uzz77bMu/2s+ZM8fWrVtnH3zwgW3YsMF2\n7txpd9xxR8v2u3fvtn379tnWrVvtN7/5zUF/DmZmPXr0sJdfftmqq6ttwYIFdu2119qKFSvkvcvL\ny23nzp328MMP25VXXtnSHtPWcQFwiAegS3v00Ue9nj17HnCb2267zZsxY4bneZ63efNmz8y8aDTq\n7d6920tKSvLq6upatn388ce9iRMnep7neQsWLPAGDBjQ8rv9+/d7Zubt2rXL8zzPmzBhgvfAAw+0\neYz79u3zBg0a5NXX13uPPfaYN3v27M/ddvv27V5RUZH3+OOPt/r7n/zkJ97UqVO99evXt7lfM/PW\nr1/vzZo1y7vvvvu8X//6194VV1zhrV+/3vv75bGtz8Dvueee80444YSW3LdvX++RRx5pyT/+8Y+9\nq666qtXXLliwwBs7dqy89tFHH23J06ZN866++uqWPG/ePO+CCy5o9b0qKio8M/MqKyu95uZmLzEx\n0VuzZk3L72+55ZaWfT355JPeuHHj5PVXXnmlN3fu3Fbfe8KECV5qaqqXlZXlFRUVeZdddplXVlbm\nxeNxLy0tzduwYUPLtm+++abXr18/z/M877XXXvMikYhXX1/f6vu29hkcyAUXXODde++9Le+dkJDg\n1dbWtvx++vTp3h133HFQx9WrV6+D2ieAzi/xqFbeAA67vLw8Ky8vt+bmZktMbN9XfuvWrRaNRq2w\nsLDlZ/F4vGVimplZQUFBy3+npaWZ2d8mrx2MF1980WbOnGnRaNSam5utoKDA9u/fbykpKfbYY4/Z\nK6+8YieddFLL9nv27LHJkyfb7Nmz7dJLL231PX/84x/b3LlzbfLkyWZmduWVV9q//Mu/HPA4Zs6c\naTfddJN5nmd33XVXuz6DsrIy+8EPfmDLly+3mpoai8fjgZ5h/2dUUlJyEJ/O3/Ts2bPlv1NTUwP5\n7591LBazW265xZ5++mnbs2ePhcN/+z/2ysvLrb6+3pqbm+W8ffa/t27dam+//bZlZ2e3/Ky5udku\nv/zyzz2uefPm2RVXXCE/Kysrs7q6upb2FbO//cv4Z1cO6d69u6WkpBz0n/+zFi1aZLfffrutW7fO\n4vG41dXV2YgRI1p+n5OTY926dWvJffv2tZKSEtuzZ0+bxwXAHbQ9AF3c6aefbikpKfb888+3+7XF\nxcWWnJxs5eXlLW0B1dXVB/V/h5tZmysmTJ061SorK+3yyy+3hx56yCorKy03N9f27NljlZWVUvhW\nVFTY5MmTberUqXbLLbd87ntmZGTYL37xC9u0aZO99NJLds8999irr756wOMYP3687dq1y0pLSwMr\nDbT1Gdx0000WCoVs1apVVl1dbY8++qh5ntfWR3PIPf744/bCCy/YK6+8YlVVVbZlyxYz+1uR1717\nd0tMTLQdO3a0bL99+/aW/y4uLrYJEya0/PkqKyuttrbWfv3rX7frGPLz8y01NdVWr17d8j5VVVXy\nl6EvuopGY2OjXXzxxXbDDTdYaWmpVVZW2te+9jX5rCsqKmz//v0tedu2bVZUVHRQxwXAHRS/QBeX\nlZVld9xxh11zzTX2/PPPW11dnUWjUVu0aJHdeOONB3xtYWGhTZ482a6//nqrrq62eDxuGzdutNdf\nf/2g9t2zZ0/btGlTm9v9fXWHzZs3W2FhYeBfBqurq+2cc86xsWPH2n/+538e8L1efvll27Bhg3me\n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\np2RbVB88Eu2r5yPp4+D5+PC54ZI/atKctUXvL4PKtcaIlFToMdXpfKjSU4P9u6OzN0k+PVmvYzHf\n3ISOdE3pOEcCAAAAHGYUvwAAAHAGxS8AAACc0eV7fttan3X2lgskJ1V6gW1KxuvHlLxPf9+Yqz1U\nfokV+vr363S9vV5J2mtjZhYNHgYOI3+Pr9+r9cmSf//amMA2RWW+fvKrSyVPz9G1W6dv/Krkqibt\nuXxp6DOS6QHuHI5N0vM4NFL7OVv+Q4Vv+Pl7fEuiOZLnvXqO5PxP9fVNl/kuUmY2p7+uKz02mXWk\nD7e2PtOJvnV/55ywOLDNvSlnSs5YoWvAFiyrlhz/WNfkjU46UfLPZ2uPr7+/F0fevpieg25h7ced\nPmKF5BdSdF6RmVl8k46L5H1al9T00jokUqu1UaRZs3e6LgAdn6Br+pqZTcnVtYD996i27qtHE1c7\nAAAAOIPiFwAAAM6g+AUAAIAzulzPb1vrs+6K6dp1H2wrlhwaGHzPeKGuk5g+SnuszijYKPnDCu3X\nK3+ij+TXT9BnZF9erOu/mvG3kqOt1tMerFvXfkNy/xeCfXKbLtS+4DOzdL3XSxd/T3JijT7/PVKt\nY/WeHiP1GPK1l8+stXWrGTmdQb2nPX1vN+ZJrozpmpq/XTtWcmKdnuc+s9ZLvqvP84F99kvU9WIZ\nK0fftmbfWqrRrMA2tbu0l7Nnla7XGmrSvmFvjPZqbrlQb/Pv1A2QfELy+4F99kgIrumKwyfF911M\n8fX89kneK/n0PlsC71GSp2Nn2z6dJ1C/Vc9pQlT7c5NX6T1t43Sdu/CNfisD+zwvbY/vJ/qeHfka\n03GPDAAAADjEKH4BAADgDIpfAAAAOKPL9fzGTRfIrY1rH0tGWPssnxlzn+S9ce2LMzPbHtV+vAmp\n+jzrPr5euvezdT3Xq5J/KLlkRaHuQNuOzcysd2Jq8Ic4ZPy9sv5xc8uuiZITH9Ex0JQZXL8wpUz/\nLrlqvvbs5vpOaTRde3yLn94m+eUxx0lurefXf9wJgS1wtLXW9/Zeg14zdkZzJT+wcZzkhk0ZkotP\nLJF8e/FLkv39vZ93HDiyymL7JT9YcbrkRduHBV6TVKHf6lCz9vhu+E4PydEsXa81lKY9wmtqCyTv\nz2plUXkuJEdUToJ+X8el6Nr/xYm6xm5BYlXgPSqz9D3qCnQOyn1hvaZ0f0TvYVVf0V7wU09dK/kS\n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\nUPwCAADAGf8fPqksilWKXgoAAAAASUVORK5CYII=\n",
            "text/plain": [
              "<Figure size 1200x500 with 10 Axes>"
            ]
          },
          "metadata": {
            "tags": []
          },
          "output_type": "display_data"
        },
        {
          "data": {
            "image/png": "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\nJ+q+R44caSUmJlqpqalWQUGBdc0111hlZWVWOBy2kpKSrK1bt0a2XbdundWzZ0/Lsizr/ffft+Li\n4qyGhoao+432GhzJhAkTrMceeyyyb4/HY9XW1kYenzRpkvXggw+26Ly6dOnSomMCiH3eE5q8AbS5\nzMxMqaiokGAwKF5v637ld+7cKYFAQPLz8yM/C4fDkYlpIiJ5eXmRPyclJYnI95PXWuK1116TqVOn\nSiAQkGAwKHl5eVJXVycJCQmyePFiWblypQwZMkQ9JyEhQa6++moZMGCADB48WE4//XT1+F133SVz\n5syRiy++WEREbrrpJvn1r399xPOYOnWq3HPPPWJZlsydO7dVr0FZWZncdtttsmbNGqmpqZFwOOzo\nGba/RsXFxS16fUREcnNzI39OTEx01D+81qFQSO677z75+9//LuXl5eJ2f/8/9ioqKqShoUGCwaB6\n3w79886dO+WTTz6RtLS0yM+CwaBMmTLlsOc1f/58ueGGG9TPysrKpL6+PtK+IvL9N+OHrhySnZ0t\nCQkJLf77H2rFihXywAMPSGFhoYTDYamvr5fTTjst8nh6erokJydH6h49ekhxcbGUl5c3e14AzEHb\nA9DBDR06VBISEmTp0qWtfm63bt0kPj5eKioqIm0BBw4caNH/DheRZldMGD9+vPj9fpkyZYosWrRI\n/H6/ZGRkSHl5ufj9fkfwPVQgEJDvvvvO8fPOnTvLI488It99950sW7ZMHn30UXn33XePeB4jRoyQ\nffv2SWlpqWOlgeZeg3vuuUdcLpds3rxZDhw4IM8//7xYlnXE47WFJUuWyKuvviorV66U6upq2bFj\nh4h8H/Kys7PF6/XKnj17Itvv3r078udu3brJyJEjI38/v98vtbW18vjjj7fqHLKysiQxMVG++uqr\nyH6qq6vVP4aOdhWNpqYmufzyy2XmzJlSWloqfr9fLrnkEvVaV1VVSV1dXaTetWuXFBQUtOi8AJiD\n8At0cKmpqfLggw/KLbfcIkuXLpX6+noJBAKyYsUKufvuu4/43Pz8fLn44ovlzjvvlAMHDkg4HJZt\n27bJqlWrWnTs3NzcqAHV7ofVHbZv3y75+fmObwY//vhjWbt2rRw8eFAaGhpk7ty5UlpaKueee65j\nX8uXL5etW7eKZVmSkpIiHo+n2WXbXC6XLFu2TF577TVHOGvuNaipqRGfzydpaWmyd+/eqJMIj4ea\n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\nADCG8T2/9h7fsDgXGR+y7kZVD3igQtVWku7pK77rfFV3ef+Aqpsy9DGiLWyO9i3ae9Zk6YXJl/r1\nIuJdbD1ZrtQUVbv716raflMLex+4CL3g7VGSW/fz9u1U4tjm/H/drOrcCfoa8X6JXrDe9Tvdn+et\n1wvQ14T1MRkrsSFaj6/dGfH6WvPaVY+o+q7zLld1yXM9Ve3bUKfqyouyVX1hsp578L1OUX6GY6U2\n3Gj7ie759dh+f1+sPlvVvk3OeQSdtumbm7jP1jc3mfvxWFWnfKPjX+J+/fnVUKMfrw85+3vt+ckt\n+rrUnnvD2++ZAQAAAMcY4RcAAADGIPwCAADAGMb1/Np7Ne09KrPLznI8p+cfdP9NU49MVVfO0L2c\nvk6lqvb8XS+gN/BM3TMcrS8mHGW9YbRv+8N6/cyVu/W6vbmffKnqg8P0Wq1X9FvfNieG48q+dmt5\nKN2xTWmjXvv7i0q91mrgdd2XmV6pV/70nqqP0dWr12V1i17jE+1Ti3oibe3bHpe+zpQs7qnqzKc+\nUnXojIGqHv1v+vFBnZz9o/ZezjgXHePHUmkoaPuJ7vn1h3V/7dryPqrO3tTk2Gdwn55b0GVZoq3W\n21tJ+hiukB5owUR93fq4qpfjmIGMTaqOj6FIyTe/AAAAMAbhFwAAAMYg/AIAAMAYsdOg0Ubs62G+\n/MYwxzYnle9R9Xd3Zqj6oQErVD33kWtUHeii+/HGZb+j6mhrxtp7kdG+RFtHdU9Q91jJW3qcWEHd\n57V3hN7+4s5fHPGYjIn2qd7W6/1+o16/ecbqqxzPyXtXX3ozN/v1Bjv1WKgZc4qqJ/VZo+o0t95f\ng6XPSUTE53L2duLEqg7rz4bldV0d23x04CRVX5u5TtWVZ+j+XN9YvSZsuJO+bjSE9Bq+zjVnRRJd\nrPPbluKauZQnuPRnxfDsbap+aYRznGRk6nXlxaUPkvbpPv1wpV5bvGFggar3jdSfcXcVrHUcM8k2\nTtrzur52sXOmAAAAwI9E+AUAAIAxCL8AAAAwhvE9v7uCuucq/WtnL6eE9c/ivkhW9R9W6h7fnJf0\neq7f3X2qqkcmFdkO4OzFi6XeGRPZ18EUEXnZr3uu8ldV6g0G9FVl1gjdg5Xt0WNRxNZDHIW9X5xx\n0/bs6/h+o0v5066LVN3rBec1JfHL7aoOVeixYu8PT95eq+pF6/XchHe76zWl+6bqdYFFRP49911V\n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\nfZyeKt2TlVCi120sDzv7OFP452tM2hfSfZhzP7xE1T2+1mOn8jQ9r+CXP3lL1dkevfYrYkOCS18T\nnnr3Xxzb9Fu3SdVNo89SdYNPf37U5ej63F768yrbzRq+sS5a/+37p76s6j917a3q19fqsdUpX9+P\noFTHGJmYrnt+O9q9B/joBAAAgDEIvwAAADAG4RcAAADG6HA9v82xr+O7Jk73/GY/8ZHjObs/1+vl\nFeYOVLVvl21txjOSVTk8+Vu9vUv376H9a7T0upc1vZ09wjn/9ZWqEzvrPmF3RpqqwxX79T5H63Hl\nGVzd6vPEiWfvHw9KyLHNf1VcoOqcNfpSXJevt/deWKHqsxO3qzrZpdcNTnX7WnSuOLHqLP2+p2yL\n8n1Uv56qDCXqnl7ft1Wqrs/Ua5CndWrQz7etAc36zx3D3lC9qud/oO9HMGBHsarLf6LXjz5jSJGq\nh8Tr/Yl0ErtYHjuxe+YAAABAKxF+AQAAYAzCLwAAAIzR4Xp+m+tBuaqz7o8q+H9PqPq6UTc6ntPv\nyUZV+zbuUXXNEL0ea68rde/MOfG6X7S5NWVx/DU3bk7vpHsuzx/2tWObL6afr+r8d0pUHUrRazOW\njdXjpnaUXqt15oD3Vd3Lm+A4Ziz3XJkiZDnXZ95Zn6HqoG3ZzqqB+hoxo/cnqo6z9fjme5z9eGj/\n0tx6vee64bWObUrCeqzkr9SLjAfyU1RdeZ4eG/+aptepT3U7ryNo3+yZIdqau+/V63V9U7/SveGh\n7FRV+/vp58/OX6tqn22cdLTcwicnAAAAjEH4BQAAgDEIvwAAADAG4RcAAADGcFlWlNkYbSRc0vd4\nHarFWtLEvemgnkDw3H49selsn15w/ipfuao76qQkd15R8xsdhfY4TlqiNqwnRv53TU9Vb2/KVvWp\niXri5JkJurZPcItz6QkMsaKtxolIbIyVaNeYWqtJ1Z806klLKW49lrI9+kYFWR49FlLdthlzMcr0\nsbKpqcnxs+U1p6s63asnxnaJ05O4z43XE21T3XoyZJK7Y0yO5PNH+7BRX2euX/8LVYfDOof0yy9T\n9Ut9/0fViS49TmI1xxxunMTm3wYAAAA4CoRfAAAAGIPwCwAAAGPQ83sMFm6O1V6YH4ueK80+luzj\normx1lHHkel9nGg5xopTa68rHfU6YsfnjxawQqquDev+8TjbuLDPIYl36ZtxdRT0/AIAAMB4hF8A\nAAAYg/ALAAAAY3hP9AmcaC3pj7L3VIXF1iZtaM8VNHp8cbRM7dtE6x2LeSroeOw9vCnuhMNsCRG+\n+QUAAIBBCL8AAAAwBuEXAAAAxjC+57cl7P13nsNsBxyKvk20FGMFh8PYwNFg3BwZrw4AAACMQfgF\nAACAMQi/AAAAMAbhFwAAAMYg/AIAAMAYhF8AAAAYg/ALAAAAYxB+AQAAYAzCLwAAAIxB+AUAAIAx\nCL8AAAAwBuEXAAAAxiD8AgAAwBiEXwAAABiD8AsAAABjEH4BAABgDMIvAAAAjEH4BQAAgDEIvwAA\nADAG4RcAAADGIPwCAADAGIRfAAAAGIPwCwAAAGMQfgEAAGAMwi8AAACMQfgFAACAMQi/AAAAMAbh\nFwAAAMZwWZZlneiTAAAAAI4HvvkFAACAMQi/AAAAMAbhFwAAAMYg/AIAAMAYhF8AAAAYg/ALAAAA\nYxB+AQAAYAzCLwAAAIxB+AUAAIAxCL8AAAAwBuEXAAAAxiD8AgAAwBiEXwAAABiD8AsAAABjEH4B\nAABgDMIvAAAAjEH4BQAAgDEIvwAAADAG4RcAAADGIPwCAADAGIRfAAAAGIPwCwAAAGMQfgEAAGCM\n/wNNV9s3jKDF5wAAAABJRU5ErkJggg==\n",
            "text/plain": [
              "<Figure size 1200x500 with 10 Axes>"
            ]
          },
          "metadata": {
            "tags": []
          },
          "output_type": "display_data"
        },
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAr8AAAFPCAYAAABEY6ZqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBo\ndHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzt3Xt8VNW5//Fnksk9IQlJSEJIuIjc\nFKoCVVAEK1qxAopgiwjWgyJFpeINUVuoP6WHUqhStKhVBIFaLxWVikWsKIgHRKQIgiTc7yGQhIRc\nJ7PPH/7M8Vk7ZoICycz6vF8vXy++kz17b2ZW9jyMz1rb4ziOIwAAAIAFwhr7BAAAAIAzheIXAAAA\n1qD4BQAAgDUofgEAAGANil8AAABYg+IXAAAA1qD4BSBTpkyRm266SURE9uzZI/Hx8VJTU9PIZwU0\n3IoVK6RVq1Zn/LkAgg/FL2CJRYsWSY8ePSQ+Pl4yMzNlwIABsmrVKtd2OTk5UlpaKuHh4T/4mP36\n9ZO//vWvDdq2tLRUsrOzRUTkhRdekHvuuafO7ebNmycej0ftd8qUKTJlypSTPj+PxyPp6eni8/lq\nH/P5fNKiRQvxeDwnvb8f6sUXX5RLLrnkjB/3ZPXr10+io6MlPj5eUlNTZciQIXLw4MFTsu9geQ0A\nBC+KX8ACM2fOlLvvvlseeughOXz4sOzZs0fGjRsnb775ZmOfWq3PP/9czj//fBER+eyzz+SCCy5w\nbVNYWCi///3v5Zxzzjllx01KSpKlS5fW5nfeeUeSk5NP2f5D1ezZs6W0tFS2bdsmRUVFMmHChJPe\nx7f/0QEAZwrFLxDiiouL5be//a089dRTMmTIEImLi5OIiAgZOHCgTJ8+3bX9rl27xOPx1BYmxcXF\nMnr0aMnMzJSsrCx55JFHalsivvmW7r777pPk5GRp27ZtbSH58MMPy8qVK+XOO++U+Ph4ufPOO+s9\nz3Xr1kn37t1r/1xX8Ttp0iQZP368pKamfud+CgoK5JprrpGkpCRp3ry59OnTR/x+/3duP3LkSJk/\nf35tnj9/vowaNUptU99rsH37dvnJT34iKSkpkpqaKiNGjJCioqLa57Zp00b++Mc/Srdu3SQxMVF+\n/vOfS0VFRb2vxbefO336dOnWrZvExcXJ6NGj5fDhwzJgwABJSEiQ/v37S2FhYe32w4YNk4yMDElM\nTJRLL71UNm/eXPuzo0ePysCBA6VZs2bSs2dPeeSRR9Q3rFu3bpUrrrhCmjdvLh07dpRXXnmlQefY\nvHlzuf7662XTpk0iIlJZWSn33Xef5OTkSHp6uowdO1bKy8tF5P/aC6ZNmyYZGRlyyy23NOgY35g7\nd6507txZEhISpF27dvLMM8+4tpk6daqkpqZKmzZtZOHChbWP13deAOxC8QuEuE8++UQqKirkuuuu\n+17Pv/nmm8Xr9UpeXp58/vnnsmzZMtVysGbNGunYsaMUFBTIAw88IKNHjxbHceTxxx+XPn361H5D\nOHv27Dr3P3r0aElKSpKJEyfK9OnTJSkpSdatWye9e/dW3/CuXbtW1q1bJ2PHjnXt49ttDzNmzJBW\nrVrJkSNH5PDhwzJ16tR6WxiuvfZa+eijj6SoqEiKiopk5cqVMnjw4Aa/Bo7jyKRJk+TAgQOyZcsW\n2bt3r6sF45VXXpF3331Xdu7cKRs3bpQXX3yxvpdcef311+W9996Tbdu2ydtvvy0DBgyQqVOnSkFB\ngfj9fpk1a1bttgMGDJDc3FzJz8+XCy64QEaMGFH7szvuuEPi4uLk0KFDMm/ePJk3b17tz06cOCFX\nXHGF3HjjjZKfny9/+9vfZNy4cap4/i4FBQXy+uuv135rP3HiRNm2bZts2LBB8vLyZP/+/fLoo4/W\nbn/o0CE5duyY7N69W5599tkGvw4iIi1atJAlS5bI8ePHZe7cuTJhwgRZv3692ndBQYHs379f5s2b\nJ2PGjJGvvvqqQecFwCIOgJC2YMECJz09vd5tJk+e7IwYMcJxHMfZuXOnIyJOdXW1c+jQIScyMtIp\nKyur3XbRokVOv379HMdxnLlz5zpnnXVW7c9OnDjhiIhz8OBBx3Ecp2/fvs5zzz0X8ByPHTvmnH32\n2U55ebmzcOFCZ9y4cernPp/P6d69u7N69eqA+/3Nb37jDBo0yMnNzQ14XBFxcnNzndGjRztz5sxx\n/vKXvzi33nqrk5ub63xzeQz0GpjeeOMN57zzzqvNrVu3dl566aXafP/99zu33357nc+dO3euc/HF\nF6vnLliwoDYPGTLEGTt2bG2eNWuWM3jw4Dr3VVhY6IiIU1RU5Ph8Psfr9Tpbt26t/fnDDz9ce6yX\nX37ZueSSS9Tzx4wZ40yZMqXOffft29eJiYlxEhMTnZYtWzo33nijk5+f7/j9fic2NtbJy8ur3Xb1\n6tVOmzZtHMdxnA8++MCJiIhwysvL69xvXa9BfQYPHuw88cQTtfsODw93SktLa38+bNgw59FHH23Q\neWVlZTXomACCn7dRK28Ap11KSooUFBSIz+cTr/fkfuV3794t1dXVkpmZWfuY3++vnZgmIpKRkVH7\n59jYWBH5evJaQ7z11lsyatQoqa6uFp/PJxkZGXLixAmJjo6WhQsXyvLly6VHjx7y9NNPS7du3aRX\nr14B93n//ffLlClT5MorrxQRkTFjxsiDDz5Y73NGjRolkyZNEsdxZNq0aepngV6D/Px8GT9+vKxc\nuVJKSkrE7/e7eobN1+jAgQMB/x7fSE9Pr/1zTEyMK3/zWtfU1MjDDz8sr776qhw5ckTCwr7+H3sF\nBQVSXl4uPp9PvW/f/vPu3btlzZo1kpSUVPuYz+eTkSNHfud5zZo1S2699Vb1WH5+vpSVldW2r4h8\n/c34t1cOSUtLk+jo6Ab//b9t6dKl8rvf/U62bdsmfr9fysrKpGvXrrU/T05Olri4uNrcunVrOXDg\ngBw5ciTgeQGwB8UvEOJ69eol0dHRsnjxYhk6dOhJPTc7O1uioqKkoKDgpAtnEQm4YsKgQYOkqKhI\nxo4dK3379pXhw4dLenq67N69WxVI77//vnz44YfyzjvviIjIsWPH5PPPP5cNGza42ikSEhJkxowZ\nMmPGDNm8ebNcdtll0rNnT7n88su/8zz69OkjBw8eFI/HI5dccols3769wa/BpEmTxOPxyMaNGyUl\nJUUWL14csL/5dFi0aJG8+eabsnz5cmnTpo0UFxdLcnKyOI4jaWlp4vV6Zd++fdKhQwcREdm7d2/t\nc7Ozs6Vv377y3nvv/aBzSE1NlZiYGNm8ebNkZWXVuc33XUWjsrJSrr/+epk/f74MHjxYIiIi5Npr\nrxXHcWq3KSwslBMnTtQWwHv27JFzzz23QecFwB70/AIhLjExUR599FG54447ZPHixVJWVibV1dWy\ndOlSeeCBB+p9bmZmplx55ZVy7733yvHjx8Xv98v27dvlww8/bNCx09PTZceOHQG3+2Z1h507d0pm\nZqbrm8EXX3xRtmzZIhs2bJANGzZIjx49ZPLkyfL444+79rVkyRLJy8sTx3GkWbNmEh4eHnDZNo/H\nI2+//ba89dZbruIs0GtQUlIi8fHxkpSUJPv3769zEuGZUFJSIlFRUZKSkiJlZWXy0EMP1f4sPDxc\nhgwZIlOmTJGysjLZunWrmuR3zTXXyLZt2+Sll16S6upqqa6ulk8//VS2bNlyUucQFhYmt912m0yY\nMEHy8/NFRGT//v3yr3/966T24ziOVFRUqP+qqqqksrKytpBfunSpLFu2zPXcyZMnS1VVlaxcuVKW\nLFkiw4YNO2XnBSA0UPwCFrjnnntk5syZ8thjj0laWppkZ2fL7Nmz5dprrw343Pnz50tVVZV06dJF\nkpOTZejQoQ1e0/XXv/61vPbaa5KcnCzjx4+vc5vq6mrZtWuXdOjQQdavX6/+1/Q3kpKSJCMjo/a/\nyMhIadasmSQmJrq2zc3Nlf79+0t8fLz06tVLxo0bJ/369Qt4ruecc853LqFW32swefJkWb9+vSQm\nJsrPfvYzGTJkSMBjnQ6jRo2S1q1bS1ZWlnTp0kUuuugi9fPZs2dLcXGxZGRkyMiRI2X48OESFRUl\nIl9/W75s2TJ5+eWXpWXLlpKRkSETJ06UysrKkz6PadOmSfv27eWiiy6SZs2aSf/+/WsnnTXU6tWr\nJSYmxvXfrFmz5IYbbpDk5GRZtGiRDBo0SD0vIyNDkpOTpWXLljJixAiZM2eOdOrU6ZSdF4DQ4HG+\n/f+MAABWmDhxYu3KDwBgE775BQALbN26VTZu3CiO48jatWvl+eef/97L3wFAMGPCGwBYoKSkRIYP\nHy4HDhyQFi1ayL333utazxgAbEDbAwAAAKxB2wMAAACsQfELAAAAa1D8AgAAwBoUvwAAALAGxS8A\nAACsQfELAAAAa1D8AgAAwBoUvwAAALAGxS8AAACsQfELAAAAa1D8AgAAwBoUvwAAALAGxS8AAACs\nQfELAAAAa1D8AgAAwBoUvwAAALAGxS8AAACsQfELAAAAa1D8AgAAwBoUvwAAALAGxS8AAACsQfEL\nAAAAa1D8AgAAwBoUvwAAALAGxS8AAACsQfELAAAAa3jP5MH8h84+k4fDaRaWkXta9ss4CS2na5yI\nMFZCDWMFDcXnDxriu8YJ3/wCAADAGhS/AAAAsAbFLwAAAKxB8QsAAABrUPwCAADAGhS/AAAAsAbF\nLwAAAKxB8QsAAABrUPwCAADAGhS/AAAAsAbFLwAAAKxB8QsAAABrUPwCAADAGhS/AAAAsAbFLwAA\nAKxB8QsAAABrUPwCAADAGhS/AAAAsAbFLwAAAKxB8QsAAABrUPwCAADAGhS/AAAAsAbFLwAAAKxB\n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\nPhRtxVGcEwAAAABJRU5ErkJggg==\n",
            "text/plain": [
              "<Figure size 1200x500 with 10 Axes>"
            ]
          },
          "metadata": {
            "tags": []
          },
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Each client has different mean images, meaning each client will be nudging\n",
        "# the model in their own directions locally.\n",
        "\n",
        "for i in range(5):\n",
        "  client_dataset = emnist_train.create_tf_dataset_for_client(\n",
        "      emnist_train.client_ids[i])\n",
        "  plot_data = collections.defaultdict(list)\n",
        "  for example in client_dataset:\n",
        "    plot_data[example['label'].numpy()].append(example['pixels'].numpy())\n",
        "  f = plt.figure(i, figsize=(12, 5))\n",
        "  f.suptitle(\"Client #{}'s Mean Image Per Label\".format(i))\n",
        "  for j in range(10):\n",
        "    mean_img = np.mean(plot_data[j], 0)\n",
        "    plt.subplot(2, 5, j+1)\n",
        "    plt.imshow(mean_img.reshape((28, 28)))\n",
        "    plt.axis('off')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HpBrx5Jn7X5E"
      },
      "source": [
        "사용자 데이터는 노이즈가 많고 레이블이 안정적이지 않을 수 있습니다. 예를 들어, 위의 클라이언트 #2의 데이터를 살펴보면 레이블 2의 경우, 노이즈가 더 많은 평균 이미지를 생성하는 레이블이 잘못 지정된 예가 있을 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "U0pwnQZUKea2"
      },
      "source": [
        "### 입력 데이터 전처리"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lMd01egqy9we"
      },
      "source": [
        "데이터가 이미 `tf.data.Dataset`이므로 데이터세트 변환을 사용하여 전처리를 수행할 수 있습니다. 여기에서는 `28x28` 이미지를 `784`개 요소 배열로 병합하고, 개별 예를 셔플하고, 배치로 구성하고, Keras와 함께 사용할 수 있도록 특성의 이름을 `pixels` 및 `label`에서 `x` 및 `y`로 바꿉니다. 또한, 데이터세트를 `repeat`하여 여러 epoch를 실행합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "cyG_BMraSuu_"
      },
      "outputs": [],
      "source": [
        "NUM_CLIENTS = 10\n",
        "NUM_EPOCHS = 5\n",
        "BATCH_SIZE = 20\n",
        "SHUFFLE_BUFFER = 100\n",
        "PREFETCH_BUFFER=10\n",
        "\n",
        "def preprocess(dataset):\n",
        "\n",
        "  def batch_format_fn(element):\n",
        "    \"\"\"Flatten a batch `pixels` and return the features as an `OrderedDict`.\"\"\"\n",
        "    return collections.OrderedDict(\n",
        "        x=tf.reshape(element['pixels'], [-1, 784]),\n",
        "        y=tf.reshape(element['label'], [-1, 1]))\n",
        "\n",
        "  return dataset.repeat(NUM_EPOCHS).shuffle(SHUFFLE_BUFFER).batch(\n",
        "      BATCH_SIZE).map(batch_format_fn).prefetch(PREFETCH_BUFFER)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "m9LXykN_jlJw"
      },
      "source": [
        "이것이 동작하는지 확인합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "VChB7LMQjkYz"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "OrderedDict([('x', array([[1., 1., 1., ..., 1., 1., 1.],\n",
              "       [1., 1., 1., ..., 1., 1., 1.],\n",
              "       [1., 1., 1., ..., 1., 1., 1.],\n",
              "       ...,\n",
              "       [1., 1., 1., ..., 1., 1., 1.],\n",
              "       [1., 1., 1., ..., 1., 1., 1.],\n",
              "       [1., 1., 1., ..., 1., 1., 1.]], dtype=float32)), ('y', array([[2],\n",
              "       [1],\n",
              "       [2],\n",
              "       [3],\n",
              "       [6],\n",
              "       [0],\n",
              "       [1],\n",
              "       [4],\n",
              "       [1],\n",
              "       [0],\n",
              "       [6],\n",
              "       [9],\n",
              "       [9],\n",
              "       [3],\n",
              "       [6],\n",
              "       [1],\n",
              "       [4],\n",
              "       [8],\n",
              "       [0],\n",
              "       [2]], dtype=int32))])"
            ]
          },
          "execution_count": 10,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "preprocessed_example_dataset = preprocess(example_dataset)\n",
        "\n",
        "sample_batch = tf.nest.map_structure(lambda x: x.numpy(),\n",
        "                                     next(iter(preprocessed_example_dataset)))\n",
        "\n",
        "sample_batch"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JGsMvRQt9Agl"
      },
      "source": [
        "당사는 페더레이션 데이터세트를 구성하기 위한 거의 모든 구성 요소를 갖추고 있습니다.\n",
        "\n",
        "시뮬레이션에서 페더레이션 데이터를 TFF에 공급하는 방법 중 하나는 목록의 각 요소가 목록이든 `tf.data.Dataset`이든 상관없이 개별 사용자의 데이터를 보유하는 목록의 각 요소를 사용하여 간단히 Python 목록으로 만드는 것입니다. 후자를 제공하는 인터페이스가 이미 있으므로 사용해 보겠습니다.\n",
        "\n",
        "다음은 훈련 또는 평가 라운드에 대한 입력으로 주어진 사용자 세트의 데이터세트 목록을 구성하는 간단한 도우미 함수입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "_PHMvHAI9xVc"
      },
      "outputs": [],
      "source": [
        "def make_federated_data(client_data, client_ids):\n",
        "  return [\n",
        "      preprocess(client_data.create_tf_dataset_for_client(x))\n",
        "      for x in client_ids\n",
        "  ]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0M9PfjOtAVqw"
      },
      "source": [
        "이제 클라이언트를 어떻게 선택할까요?\n",
        "\n",
        "일반적인 페더레이션 훈련 시나리오에서는 잠재적으로 매우 많은 수의 사용자 기기를 다루고 있으며, 이 중 일부만 주어진 시점에서 훈련에 사용할 수 있습니다. 예를 들어, 클라이언트 기기가 전원에 연결되어 있고 데이터 통신 연결 네트워크가 꺼져 있거나 유휴 상태일 때만 훈련에 참여하는 휴대폰인 경우입니다.\n",
        "\n",
        "물론, 시뮬레이션 환경에서는 모든 데이터를 로컬에서 사용할 수 있습니다. 통상적으로, 시뮬레이션을 실행할 때 일반적으로 각 라운드마다 다른 각 훈련 라운드에 참여할 클라이언트의 무작위 하위 집합을 샘플링합니다.\n",
        "\n",
        "즉, [Federated Averaging](https://arxiv.org/abs/1602.05629) 알고리즘에 대한 논문을 연구하면 알 수 있듯이, 각 라운드에 무작위로 샘플링된 클라이언트 하위 집합이 있는 시스템에서 수렴을 달성하는 데는 시간이 걸릴 수 있으며, 이 대화형 튜토리얼에서 수백 번의 라운드를 실행해야 하는 것은 비현실적입니다.\n",
        "\n",
        "대신 클라이언트 세트를 한 번 샘플링하고 수렴 속도를 높이기 위해 라운드에서 같은 세트를 재사용할 것입니다(의도적으로 이들 소수의 사용자 데이터에 과대적합임). 독자가 이 튜토리얼을 수정하여 무작위 샘플링을 시뮬레이션하는 것은 연습으로 남겨 둡니다. 매우 쉽습니다(한 번 수행하면 모델을 수렴하는 데 시간이 걸릴 수 있음을 명심하세요)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "GZ6NYHxB8xer"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Number of client datasets: 10\n",
            "First dataset: <DatasetV1Adapter shapes: OrderedDict([(x, (None, 784)), (y, (None, 1))]), types: OrderedDict([(x, tf.float32), (y, tf.int32)])>\n"
          ]
        }
      ],
      "source": [
        "sample_clients = emnist_train.client_ids[0:NUM_CLIENTS]\n",
        "\n",
        "federated_train_data = make_federated_data(emnist_train, sample_clients)\n",
        "\n",
        "print('Number of client datasets: {l}'.format(l=len(federated_train_data)))\n",
        "print('First dataset: {d}'.format(d=federated_train_data[0]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HOxq4tbi9m8-"
      },
      "source": [
        "## Keras로 모델 만들기\n",
        "\n",
        "Keras를 사용하는 경우, Keras 모델을 구성하는 코드가 이미 있을 수 있습니다. 다음은 요구 사항에 맞는 간단한 모델의 예제입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LYCsJGJFWbqt"
      },
      "outputs": [],
      "source": [
        "def create_keras_model():\n",
        "  return tf.keras.models.Sequential([\n",
        "      tf.keras.layers.Input(shape=(784,)),\n",
        "      tf.keras.layers.Dense(10, kernel_initializer='zeros'),\n",
        "      tf.keras.layers.Softmax(),\n",
        "  ])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NHdraKFH4OU2"
      },
      "source": [
        "**참고:** 아직 모델을 컴파일하지 않습니다. 손실, 메트릭 및 옵티마이저는 나중에 소개됩니다.\n",
        "\n",
        "TFF와 함께 모델을 사용하려면, Keras와 유사하게 모델의 순방향 전달, 메타데이터 속성 등을 스탬핑하는 메서드를 노출하는 `tff.learning.Model` 인터페이스의 인스턴스로 모델을 래핑해야 하지만, 페더레이션 메트릭의 계산 프로세스를 제어하는 ​​방법과 같은 추가 요소도 도입합니다. 지금은 이것에 대해 걱정하지 마세요. 위에서 정의한 것과 같은 Keras 모델이 있는 경우, 아래와 같이 <code>tff.learning.from_keras_model</code>를 호출하고 모델과 샘플 데이터 배치를 인수로 전달하여 TFF를 래핑할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Q3ynrxd53HzY"
      },
      "outputs": [],
      "source": [
        "def model_fn():\n",
        "  # We _must_ create a new model here, and _not_ capture it from an external\n",
        "  # scope. TFF will call this within different graph contexts.\n",
        "  keras_model = create_keras_model()\n",
        "  return tff.learning.from_keras_model(\n",
        "      keras_model,\n",
        "      input_spec=preprocessed_example_dataset.element_spec,\n",
        "      loss=tf.keras.losses.SparseCategoricalCrossentropy(),\n",
        "      metrics=[tf.keras.metrics.SparseCategoricalAccuracy()])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "XJ5E3O18_JZ6"
      },
      "source": [
        "## 페더레이션 데이터에 대해 모델 훈련하기\n",
        "\n",
        "TFF와 함께 사용하기 위해 `tff.learning.Model`로 래핑한 모델이 있으므로 다음과 같이 도우미 함수 `tff.learning.build_federated_averaging_process`를 호출하여 TFF에서 Federated Averaging 알고리즘을 구성하도록 할 수 있습니다.\n",
        "\n",
        "인수는 이미 생성된 인스턴스가 아닌 생성자(예: 위의 `model_fn`)여야 하므로 모델 생성은 TFF에 의해 제어되는 컨텍스트에서 발생할 수 있습니다(그 이유가 궁금하다면, [사용자 정의 알고리즘](custom_federated_algorithms_1.ipynb)에 대한 후속 튜토리얼을 읽어 보시기 바랍니다).\n",
        "\n",
        "아래의 Federated Averaging 알고리즘에 대한 중요한 참고 사항 중 하나는 *client_optimizer* 및 *server_optimizer의* **두 가지** 옵티마이저입니다. *client_optimizer*는 각 클라이언트에서 로컬 모델 업데이트를 계산하는 데만 사용됩니다. *server_optimizer*는 평균 업데이트를 서버의 글로벌 모델에 적용합니다. 특히, 이는 사용되는 옵티마이저 및 학습률의 선택이 표준 iid 데이터세트에 대해 모델을 훈련하는 데 사용한 것과 달라야 할 수 있음을 의미합니다. 정규 SGD부터 시작하는 것이 좋습니다. 학습률이 평소보다 낮을 수 있습니다. 여기서 사용하는 학습률은 신중하게 조정되지 않았으므로 자유롭게 실험해 보세요."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sk6mjOfycX5N"
      },
      "outputs": [],
      "source": [
        "iterative_process = tff.learning.build_federated_averaging_process(\n",
        "    model_fn,\n",
        "    client_optimizer_fn=lambda: tf.keras.optimizers.SGD(learning_rate=0.02),\n",
        "    server_optimizer_fn=lambda: tf.keras.optimizers.SGD(learning_rate=1.0))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "f8FpvN2n67sm"
      },
      "source": [
        "방금 무슨 일이 있었나요? TFF에서 한 쌍의 *페더레이션 계산*을 구성하고 `tff.templates.IterativeProcess`로 패키징하여 이들 계산을 한 쌍의 속성 `initialize` 및 `next`로 사용할 수 있습니다.\n",
        "\n",
        "간단히 말해서, *페더레이션 계산*은 다양한 페더레이션 알고리즘을 표현할 수 있는 TFF의 내부 언어로 된 프로그램입니다([사용자 정의 알고리즘](custom_federated_algorithms_1.ipynb) 튜토리얼에서 자세한 내용을 찾을 수 있음). 이 경우, 생성되고 `iterative_process`로 패키징된 두 가지 계산은 [Federated Averaging](https://arxiv.org/abs/1602.05629)을 구현합니다.\n",
        "\n",
        "실제 페더레이션 학습 설정에서 실행될 수 있는 방식으로 계산을 정의하는 것이 TFF의 목표이지만, 현재는 로컬 실행 시뮬레이션 런타임만 구현됩니다. 시뮬레이터에서 계산을 실행하려면 Python 함수처럼 간단히 호출하면 됩니다. 이 기본 해석 환경은 고성능을 위해 설계되지 않았지만, 이 튜토리얼에는 충분합니다. 향후 릴리스에서 대규모 연구를 용이하게 하기 위해 고성능 시뮬레이션 런타임을 제공할 것으로 기대합니다.\n",
        "\n",
        "`initialize` 계산부터 시작하겠습니다. 모든 페더레이션 계산의 경우와 마찬가지로 이를 함수로 생각할 수 있습니다. 계산은 인수를 사용하지 않고 하나의 결과를 반환합니다. 즉, 서버에서 Federated Averaging 프로세스의 상태를 나타냅니다. TFF의 세부 사항에 대해 자세히 알아보고 싶지는 않지만, 이 상태가 어떻게 생겼는지 확인하는 것이 도움이 될 수 있습니다. 다음과 같이 시각화할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Z4pcfWsUBp_5"
      },
      "outputs": [
        {
          "data": {
            "application/vnd.google.colaboratory.intrinsic": {
              "type": "string"
            },
            "text/plain": [
              "'( -> <model=<trainable=<float32[784,10],float32[10]>,non_trainable=<>>,optimizer_state=<int64>,delta_aggregate_state=<>,model_broadcast_state=<>>@SERVER)'"
            ]
          },
          "execution_count": 16,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "str(iterative_process.initialize.type_signature)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v1gbHQ_7BiyT"
      },
      "source": [
        "위의 형식 서명이 처음에는 다소 모호해 보일 수 있지만, 서버 상태는 `model`(모든 기기에 배포될 MNIST의 초기 모델 매개변수)과 `optimizer_state`(서버에서 유지 관리하는 추가 정보, 하이퍼 매개변수 일정 등에 사용할 라운드 수 등)로 구성됩니다..\n",
        "\n",
        "`initialize` 계산을 호출하여 서버 상태를 구성해 보겠습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6cagCWlZmcch"
      },
      "outputs": [],
      "source": [
        "state = iterative_process.initialize()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "TjjxTx9e_rMd"
      },
      "source": [
        "두 번째 페더레이션 계산 쌍인 `next`는 서버 상태(모델 매개변수 포함)를 클라이언트에 푸시, 로컬 데이터에 대한 기기 내 훈련, 모델 업데이트 수집 및 평균화로 구성된 단일 라운드의 페더레이션 평균화를 나타내며, 서버에서 업데이트된 새 모델을 생성합니다.\n",
        "\n",
        "개념적으로, `next`과 같은 함수형 형식 서명을 갖는 것으로 생각할 수 있습니다.\n",
        "\n",
        "```\n",
        "SERVER_STATE, FEDERATED_DATA -> SERVER_STATE, TRAINING_METRICS\n",
        "```\n",
        "\n",
        "특히, `next()`는 서버에서 실행되는 함수가 아니라 전체 분산 계산의 선언적 함수형 표현으로 생각해야 합니다. 일부 입력은 서버( `SERVER_STATE`)에서 제공하지만, 참여하는 각 기기는 자체 로컬 데이터트를 제공합니다.\n",
        "\n",
        "라운드 한 번 훈련을 실행하고 결과를 시각화해 보겠습니다. 사용자 샘플을 위해 위에서 이미 생성한 페더레이션 데이터를 사용할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "F3M_W9dDE6Tm"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "round  1, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.12037037312984467,loss=3.0108425617218018>>\n"
          ]
        }
      ],
      "source": [
        "state, metrics = iterative_process.next(state, federated_train_data)\n",
        "print('round  1, metrics={}'.format(metrics))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UmhReXt9G4A5"
      },
      "source": [
        "몇 라운드를 더 실행해 봅시다. 앞서 언급했듯이, 일반적으로 이 시점에서 사용자가 지속적으로 오고가는 현실적인 배포를 시뮬레이션하기 위해 각 라운드에서 무작위로 선택한 새로운 사용자 샘플에서 시뮬레이션 데이터의 하위 집합을 선택하지만, 이 대화형 노트북에서는 데모를 위해 같은 사용자를 재사용하여 시스템이 빠르게 수렴되도록 합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qrJkQuCRJP9C"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "round  2, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.14814814925193787,loss=2.8865506649017334>>\n",
            "round  3, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.148765429854393,loss=2.9079062938690186>>\n",
            "round  4, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.17633745074272156,loss=2.724686622619629>>\n",
            "round  5, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.20226337015628815,loss=2.6334855556488037>>\n",
            "round  6, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.22427983582019806,loss=2.5482592582702637>>\n",
            "round  7, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.24094650149345398,loss=2.4472343921661377>>\n",
            "round  8, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.259876549243927,loss=2.3809611797332764>>\n",
            "round  9, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.29814815521240234,loss=2.156442403793335>>\n",
            "round 10, metrics=<broadcast=<>,aggregation=<>,train=<sparse_categorical_accuracy=0.31687241792678833,loss=2.122845411300659>>\n"
          ]
        }
      ],
      "source": [
        "NUM_ROUNDS = 11\n",
        "for round_num in range(2, NUM_ROUNDS):\n",
        "  state, metrics = iterative_process.next(state, federated_train_data)\n",
        "  print('round {:2d}, metrics={}'.format(round_num, metrics))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "joHYzn9jcs0Y"
      },
      "source": [
        "페더레이션 훈련의 각 라운드 후에 훈련 손실이 감소하여 모델이 수렴되고 있음을 나타냅니다. 이러한 훈련 메트릭에는 몇 가지 중요한 주의 사항이 있지만, 이 튜토리얼 뒷부분의 *평가* 섹션을 참조하세요."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ruSHJl1IjhNf"
      },
      "source": [
        "## TensorBoard에 모델 메트릭 표시, 다음으로 Tensorboard를 사용하여 이들 페더레이션 계산의 메트릭을 시각화해 보겠습니다.\n",
        "\n",
        "메트릭을 기록할 디렉터리와 해당 요약 작성기를 만드는 것으로 시작하겠습니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "E3QUBK41lWDW"
      },
      "outputs": [],
      "source": [
        "#@test {\"skip\": true}\n",
        "logdir = \"/tmp/logs/scalars/training/\"\n",
        "summary_writer = tf.summary.create_file_writer(logdir)\n",
        "state = iterative_process.initialize()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "w-2aGxUlzS_J"
      },
      "source": [
        "같은 요약 작성기를 사용하여 관련 스칼라 메트릭을 플롯합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "JZtr4_8lzN-V"
      },
      "outputs": [],
      "source": [
        "#@test {\"skip\": true}\n",
        "with summary_writer.as_default():\n",
        "  for round_num in range(1, NUM_ROUNDS):\n",
        "    state, metrics = iterative_process.next(state, federated_train_data)\n",
        "    for name, value in metrics.train._asdict().items():\n",
        "      tf.summary.scalar(name, value, step=round_num)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "iUouyAHG0Mk8"
      },
      "source": [
        "위에 지정된 루트 로그 디렉터리로 TensorBoard를 시작합니다. 데이터를 로드하는 데 몇 초 정도 걸릴 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "urYYcmA9089p"
      },
      "outputs": [],
      "source": [
        "#@test {\"skip\": true}\n",
        "%tensorboard --logdir /tmp/logs/scalars/ --port=0"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ZMcV15W7b1wG"
      },
      "outputs": [],
      "source": [
        "#@test {\"skip\": true}\n",
        "# Run this this cell to clean your directory of old output for future graphs from this directory.\n",
        "!rm -R /tmp/logs/scalars/*"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jejrFEVP1EDs"
      },
      "source": [
        "같은 방식으로 평가 메트릭을 보려면 \"logs/scalars/eval\"과 같은 별도의 eval 폴더를 만들어 TensorBoard에 쓸 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "T4hneAcb-F2l"
      },
      "source": [
        "## 모델 구현 사용자 정의하기\n",
        "\n",
        "Keras는 [TensorFlow용으로 권장되는 상위 수준 모델 API](https://medium.com/tensorflow/standardizing-on-keras-guidance-on-high-level-apis-in-tensorflow-2-0-bad2b04c819a)이며, 가능하면 TFF에서 Keras 모델(`tff.learning.from_keras_model`를 통해)을 사용하는 것이 좋습니다.\n",
        "\n",
        "그러나 `tff.learning`은 페더레이션 학습을 위해 모델을 사용하는 데 필요한 최소한의 기능을 노출하는 하위 수준 모델 인터페이스 인 `tff.learning.Model`을 제공합니다. 이 인터페이스(아마도 `tf.keras.layers`와 같은 구성 요소를 계속 사용)를 직접 구현하면 페더레이션 학습 알고리즘의 내부를 수정하지 않고도 최대한으로 사용자 정의가 가능합니다.\n",
        "\n",
        "처음부터 다시 한번 해봅시다.\n",
        "\n",
        "### 모델 변수, 순방향 전달 및 메트릭 정의하기\n",
        "\n",
        "첫 번째 단계는 작업할 TensorFlow 변수를 식별하는 것입니다. 다음 코드를 더 읽기 쉽게 만들기 위해 전체 집합을 나타내는 데이터 구조를 정의하겠습니다. 여기에는 훈련할 `weights`와 `bias`와 같은 변수와 함께 `loss_sum`, `accuracy_sum` 및 `num_examples`와 같은 훈련 중에 업데이트할 다양한 누적 통계 및 카운터를 보유하는 변수도 포함됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "uqRD72WQC4u1"
      },
      "outputs": [],
      "source": [
        "MnistVariables = collections.namedtuple(\n",
        "    'MnistVariables', 'weights bias num_examples loss_sum accuracy_sum')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "nkJfDcY5oXii"
      },
      "source": [
        "다음은 변수를 생성하는 메서드입니다. 간단하게 하기 위해 모든 통계를 `tf.float32`로 표시합니다. 그러면 이후 단계에서 유형 변환이 필요하지 않습니다. 변수 이니셜라이저를 람다로 래핑하는 것은 [리소스 변수](https://www.tensorflow.org/api_docs/python/tf/enable_resource_variables)에서 요구하는 사항입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "H3GQHLNqCfMU"
      },
      "outputs": [],
      "source": [
        "def create_mnist_variables():\n",
        "  return MnistVariables(\n",
        "      weights=tf.Variable(\n",
        "          lambda: tf.zeros(dtype=tf.float32, shape=(784, 10)),\n",
        "          name='weights',\n",
        "          trainable=True),\n",
        "      bias=tf.Variable(\n",
        "          lambda: tf.zeros(dtype=tf.float32, shape=(10)),\n",
        "          name='bias',\n",
        "          trainable=True),\n",
        "      num_examples=tf.Variable(0.0, name='num_examples', trainable=False),\n",
        "      loss_sum=tf.Variable(0.0, name='loss_sum', trainable=False),\n",
        "      accuracy_sum=tf.Variable(0.0, name='accuracy_sum', trainable=False))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SrdnR0fAre-Q"
      },
      "source": [
        "모델 매개변수 및 누적 통계에 대한 변수를 사용하여 다음과 같이 손실을 계산하고, 예측값을 내보내고, 단일 배치의 입력 데이터에 대한 누적 통계를 업데이트하는 순방향 전달 메서드를 정의할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ZYSRAl-KCvC7"
      },
      "outputs": [],
      "source": [
        "def mnist_forward_pass(variables, batch):\n",
        "  y = tf.nn.softmax(tf.matmul(batch['x'], variables.weights) + variables.bias)\n",
        "  predictions = tf.cast(tf.argmax(y, 1), tf.int32)\n",
        "\n",
        "  flat_labels = tf.reshape(batch['y'], [-1])\n",
        "  loss = -tf.reduce_mean(\n",
        "      tf.reduce_sum(tf.one_hot(flat_labels, 10) * tf.math.log(y), axis=[1]))\n",
        "  accuracy = tf.reduce_mean(\n",
        "      tf.cast(tf.equal(predictions, flat_labels), tf.float32))\n",
        "\n",
        "  num_examples = tf.cast(tf.size(batch['y']), tf.float32)\n",
        "\n",
        "  variables.num_examples.assign_add(num_examples)\n",
        "  variables.loss_sum.assign_add(loss * num_examples)\n",
        "  variables.accuracy_sum.assign_add(accuracy * num_examples)\n",
        "\n",
        "  return loss, predictions"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-gm-yx2Mr_bl"
      },
      "source": [
        "다음으로 다시 TensorFlow를 사용하여 로컬 메트릭 세트를 반환하는 함수를 정의합니다. 로컬 메트릭 세트는 페더레이션 학습 또는 평가 프로세스에서 서버로 집계할 수 있는 값(자동으로 처리되는 모델 업데이트에 추가)입니다.\n",
        "\n",
        "여기서는 단순히 평균 `loss` 및 `accuracy`와 `num_examples`를 반환하며, 페더레이션 집계를 계산할 때 다른 사용자의 기여도에 올바르게 가중치를 적용해야 합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "RkAZXhjGEekp"
      },
      "outputs": [],
      "source": [
        "def get_local_mnist_metrics(variables):\n",
        "  return collections.OrderedDict(\n",
        "      num_examples=variables.num_examples,\n",
        "      loss=variables.loss_sum / variables.num_examples,\n",
        "      accuracy=variables.accuracy_sum / variables.num_examples)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9ywGs1G-s1o3"
      },
      "source": [
        "마지막으로, `get_local_mnist_metrics`를 통해 각 기기에서 내보낸 로컬 메트릭을 집계하는 방법을 결정해야 합니다. 이것은 TensorFlow로 작성되지 않은 코드의 유일한 부분입니다. TFF로 표현된 *페더레이션 계산*입니다. 더 자세히 알고 싶다면, [사용자 정의 알고리즘](custom_federated_algorithms_1.ipynb) 튜토리얼을 살펴보지만, 대부분의 애플리케이션에서는 그럴 필요가 없습니다. 아래 표시된 패턴의 변형으로 충분합니다. 다음과 같습니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "BMr2PwkfExFI"
      },
      "outputs": [],
      "source": [
        "@tff.federated_computation\n",
        "def aggregate_mnist_metrics_across_clients(metrics):\n",
        "  return collections.OrderedDict(\n",
        "      num_examples=tff.federated_sum(metrics.num_examples),\n",
        "      loss=tff.federated_mean(metrics.loss, metrics.num_examples),\n",
        "      accuracy=tff.federated_mean(metrics.accuracy, metrics.num_examples)) "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2rXZ3Hg44aeN"
      },
      "source": [
        "입력 `metrics` 인수는 위의 `get_local_mnist_metrics`에서 반환한 `OrderedDict`에 해당하지만, 결정적으로 해당 값은 더 이상 `tf.Tensors`가 아닙니다. `tff.Value`로 \"박스화\"되어 있으므로 더 이상 TensorFlow를 사용하여 조작할 수 없지만, `tff.federated_mean` 및 `tff.federated_sum`과 같은 TFF의 페더레이션 연산자만 사용할 수 있습니다. 반환된 전역 집계 사전은 서버에서 사용할 수 있는 메트릭 세트를 정의합니다.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "7MXGAuQRvmcp"
      },
      "source": [
        "### `tff.learning.Model`의 인스턴스 생성하기\n",
        "\n",
        "위의 모든 항목이 준비되었으므로 TFF가 Keras 모델을 수집하도록 할 때 생성되는 것과 유사한 TFF와 함께 사용할 모델 표현을 구성할 준비가 되었습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "blQGiTQFS9_r"
      },
      "outputs": [],
      "source": [
        "class MnistModel(tff.learning.Model):\n",
        "\n",
        "  def __init__(self):\n",
        "    self._variables = create_mnist_variables()\n",
        "\n",
        "  @property\n",
        "  def trainable_variables(self):\n",
        "    return [self._variables.weights, self._variables.bias]\n",
        "\n",
        "  @property\n",
        "  def non_trainable_variables(self):\n",
        "    return []\n",
        "\n",
        "  @property\n",
        "  def local_variables(self):\n",
        "    return [\n",
        "        self._variables.num_examples, self._variables.loss_sum,\n",
        "        self._variables.accuracy_sum\n",
        "    ]\n",
        "\n",
        "  @property\n",
        "  def input_spec(self):\n",
        "    return collections.OrderedDict(\n",
        "        x=tf.TensorSpec([None, 784], tf.float32),\n",
        "        y=tf.TensorSpec([None, 1], tf.int32))\n",
        "\n",
        "  @tf.function\n",
        "  def forward_pass(self, batch, training=True):\n",
        "    del training\n",
        "    loss, predictions = mnist_forward_pass(self._variables, batch)\n",
        "    num_exmaples = tf.shape(batch['x'])[0]\n",
        "    return tff.learning.BatchOutput(\n",
        "        loss=loss, predictions=predictions, num_examples=num_exmaples)\n",
        "\n",
        "  @tf.function\n",
        "  def report_local_outputs(self):\n",
        "    return get_local_mnist_metrics(self._variables)\n",
        "\n",
        "  @property\n",
        "  def federated_output_computation(self):\n",
        "    return aggregate_mnist_metrics_across_clients"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sMN1AszMwLHL"
      },
      "source": [
        "보시다시피, `tff.learning.Model`에서 정의한 추상 메서드 및 속성은 변수를 도입하고 손실 및 통계를 정의한 이전 섹션의 코드 조각에 해당합니다.\n",
        "\n",
        "다음은 강조할 만한 몇 가지 사항입니다.\n",
        "\n",
        "- TFF는 런타임에 Python을 사용하지 않으므로 모델에서 사용할 모든 상태를 TensorFlow 변수로 캡처해야 합니다(코드는 모바일 기기에 배포할 수 있도록 작성되어야 합니다. 그 이유에 대한 자세한 내용은 [사용자 정의 알고리즘](custom_federated_algorithms_1.ipynb) 튜토리얼을 참조하세요).\n",
        "- 일반적으로 TFF는 강력한 형식의 환경이며 모든 구성 요소에 대한 형식 서명을 결정하려고 하기 때문에 모델은 허용하는 데이터 형식(`input_spec`)을 설명해야 합니다. 모델의 입력 형식을 선언하는 것은 필수입니다.\n",
        "- 기술적으로는 필요하지 않지만, 모든 TensorFlow 로직(순방향 전달, 메트릭 계산 등)을 `tf.function`로 래핑하는 것이 좋습니다. 이렇게 하면 TensorFlow가 직렬화될 수 있고 명시적인 제어 종속성이 필요하지 않습니다.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9DVhXk2Bu-GU"
      },
      "source": [
        "위의 내용은 Federated SGD와 같은 평가 및 알고리즘에 충분합니다. 그러나 Federated Averaging의 경우 모델이 각 배치에서 로컬로 훈련하는 방법을 지정해야 합니다. Federated Averaging 알고리즘을 빌드할 때 로컬 옵티마이저를 지정합니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hVBugKP3yw03"
      },
      "source": [
        "### 새 모델로 페더레이션 훈련 시뮬레이션하기\n",
        "\n",
        "위의 모든 사항이 준빈되면, 프로세스의 나머지 부분은 이미 본 것과 같이 보입니다. 모델 생성자를 새 모델 클래스의 생성자로 교체하고 생성한 반복 프로세스에서 두 개의 페더레이션 계산을 사용하여 훈련 라운드를 순환합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "FK3c8_leS9_t"
      },
      "outputs": [],
      "source": [
        "iterative_process = tff.learning.build_federated_averaging_process(\n",
        "    MnistModel,\n",
        "    client_optimizer_fn=lambda: tf.keras.optimizers.SGD(learning_rate=0.02))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Jv_LiggwS9_u"
      },
      "outputs": [],
      "source": [
        "state = iterative_process.initialize()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "PtOLElmzDPxs"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "round  1, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.9713594913482666,accuracy=0.13518518209457397>>\n"
          ]
        }
      ],
      "source": [
        "state, metrics = iterative_process.next(state, federated_train_data)\n",
        "print('round  1, metrics={}'.format(metrics))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "gFkv0yJEGhue"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "round  2, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.975412607192993,accuracy=0.14032921195030212>>\n",
            "round  3, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.9395227432250977,accuracy=0.1594650149345398>>\n",
            "round  4, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.710164785385132,accuracy=0.17139917612075806>>\n",
            "round  5, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.5891618728637695,accuracy=0.20267489552497864>>\n",
            "round  6, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.5148487091064453,accuracy=0.21666666865348816>>\n",
            "round  7, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.2816808223724365,accuracy=0.2580246925354004>>\n",
            "round  8, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.3656885623931885,accuracy=0.25884774327278137>>\n",
            "round  9, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=2.23549222946167,accuracy=0.28477364778518677>>\n",
            "round 10, metrics=<broadcast=<>,aggregation=<>,train=<num_examples=4860.0,loss=1.974222183227539,accuracy=0.35329216718673706>>\n"
          ]
        }
      ],
      "source": [
        "for round_num in range(2, 11):\n",
        "  state, metrics = iterative_process.next(state, federated_train_data)\n",
        "  print('round {:2d}, metrics={}'.format(round_num, metrics))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Iswqa2Uj7phq"
      },
      "source": [
        "TensorBoard 내에서 이들 메트릭을 보려면, 위의 \"TensorBoard에서 모델 메트릭 표시하기\"에 나열된 단계를 참조하세요."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "m7lz59lMJ0kj"
      },
      "source": [
        "## 평가\n",
        "\n",
        "지금까지의 모든 실험은 페더레이션 훈련 메트릭(라운드의 모든 클라이언트에 걸쳐 훈련된 모든 데이터 배치에 대한 평균 메트릭)만 제시했습니다. 이는 특히 단순성을 위해 각 라운드에서 같은 클라이언트 세트를 사용했기 때문에 과대적합에 대한 일반적인 우려가 있지만, Federated Averaging 알고리즘에 특정한 훈련 메트릭에는 과대적합이라는 추가 개념이 있습니다. 이것은 각 클라이언트가 단일 데이터 배치를 가지고 있다고 상상하고 많은 반복(epoch) 동안 해당 배치에 대해 훈련하는 경우 가장 쉽게 확인할 수 있습니다. 이 경우 로컬 모델은 해당 배치 하나에 빠르게 정확히 맞으므로 평균적인 로컬 정확성 메트릭은 1.0에 접근합니다. 따라서 이들 훈련 메트릭은 훈련이 진행되고 있다는 신호로 간주될 수 있지만, 그 이상은 아닙니다.\n",
        "\n",
        "페더레이션 데이터에 대한 평가를 수행하려면, <code>tff.learning.build_federated_evaluation</code> 함수를 사용하고 모델 생성자에 인수로 전달하는, 이 용도로 설계된 또 다른 <em>페더레이션 계산</em>을 구성할 수 있습니다. `MnistTrainableModel`를 사용했던 Federated Averaging과는 달리, `MnistMode`을 전달하면 충분합니다. 평가는 경사 하강을 수행하지 않으며 옵티마이저를 구성할 필요가 없습니다.\n",
        "\n",
        "실험과 연구를 위해 중앙 집중식 테스트 데이터세트를 사용할 수 있는 경우, [텍스트 생성을 위한 페더레이션 학습](federated_learning_for_text_generation.ipynb)은 다른 평가 옵션을 보여줍니다. 페더레이션 학습에서 훈련된 가중치를 가져와 표준 Keras 모델에 적용한 다음 중앙 집중식 데이터세트에서 `tf.keras.models.Model.evaluate()`를 호출하면 됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "nRiXyqnXM2VO"
      },
      "outputs": [],
      "source": [
        "evaluation = tff.learning.build_federated_evaluation(MnistModel)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "uwfINGoNQEuV"
      },
      "source": [
        "다음과 같이 평가 함수의 추상 형식 서명을 검사할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "3q5ueoO0NDNb"
      },
      "outputs": [
        {
          "data": {
            "application/vnd.google.colaboratory.intrinsic": {
              "type": "string"
            },
            "text/plain": [
              "'(<<trainable=<float32[784,10],float32[10]>,non_trainable=<>>@SERVER,{<x=float32[?,784],y=int32[?,1]>*}@CLIENTS> -> <num_examples=float32@SERVER,loss=float32@SERVER,accuracy=float32@SERVER>)'"
            ]
          },
          "execution_count": 35,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "str(evaluation.type_signature)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "XA3v7f2SQs6q"
      },
      "source": [
        "이 시점에서 세부 사항에 대해 걱정할 필요는 없습니다. `tff.templates.IterativeProcess.next`와 비슷하지만, 두 가지 중요한 차이점이 있는 다음과 같은 일반적인 형식을 취한다는 점만 알아 두십시오. 첫째, 평가에서는 모델이나 상태의 다른 측면을 수정하지 않기 때문에 서버 상태를 반환하지 않습니다. 상태 비저장으로 생각할 수 있습니다. 둘째, 평가에는 모델만 필요하며 옵티마이저 변수와 같이 훈련과 관련될 수 있는 서버 상태의 다른 부분이 필요하지 않습니다.\n",
        "\n",
        "```\n",
        "SERVER_MODEL, FEDERATED_DATA -> TRAINING_METRICS\n",
        "```\n",
        "\n",
        "훈련 중에 도달한 최신 상태에 대한 평가를 호출해 보겠습니다. 서버 상태에서 훈련된 최신 모델을 추출하려면 다음과 같이 `.model` 멤버에 액세스하기만 하면 됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "OX4Sk_uyOaYa"
      },
      "outputs": [],
      "source": [
        "train_metrics = evaluation(state.model, federated_train_data)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UeEsdwJgRGMW"
      },
      "source": [
        "평가 결과는 다음과 같습니다. 위의 마지막 훈련 라운드에서 보고된 것보다 수치가 약간 더 좋아 보입니다. 일반적으로, 반복 훈련 프로세스에서 보고된 훈련 메트릭은 일반적으로 훈련 라운드 시작 시 모델의 성능을 반영하므로 평가 메트릭은 항상 한 단계 앞서 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zwCy1IPxOfiT"
      },
      "outputs": [
        {
          "data": {
            "application/vnd.google.colaboratory.intrinsic": {
              "type": "string"
            },
            "text/plain": [
              "'<num_examples=4860.0,loss=1.7142657041549683,accuracy=0.38683128356933594>'"
            ]
          },
          "execution_count": 37,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "str(train_metrics)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SpfgdNDoRjPy"
      },
      "source": [
        "이제 페더레이션 데이터의 테스트 샘플을 컴파일하고 테스트 데이터에 대한 평가를 다시 실행해 보겠습니다. 데이터는 실제 사용자의 같은 샘플에서 제공되지만, 별개의 보류된 데이터세트에서 제공됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "in8vProVNc04"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "(10,\n",
              " <DatasetV1Adapter shapes: OrderedDict([(x, (None, 784)), (y, (None, 1))]), types: OrderedDict([(x, tf.float32), (y, tf.int32)])>)"
            ]
          },
          "execution_count": 38,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "federated_test_data = make_federated_data(emnist_test, sample_clients)\n",
        "\n",
        "len(federated_test_data), federated_test_data[0]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ty-ZwfE0NJfV"
      },
      "outputs": [],
      "source": [
        "test_metrics = evaluation(state.model, federated_test_data)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "e5fGtIJYNqYH"
      },
      "outputs": [
        {
          "data": {
            "application/vnd.google.colaboratory.intrinsic": {
              "type": "string"
            },
            "text/plain": [
              "'<num_examples=580.0,loss=1.861915111541748,accuracy=0.3362068831920624>'"
            ]
          },
          "execution_count": 40,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "str(test_metrics)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "67vYxrDWzRcj"
      },
      "source": [
        "이것으로 튜토리얼을 마칩니다. 매개변수(예: 배치 크기, 사용자 수, epoch, 학습률 등)를 사용하여 위의 코드를 수정하여 각 라운드에서 사용자의 무작위 샘플에 대한 훈련을 시뮬레이션하고 당사의 다른 튜토리얼을 탐색하는 것이 좋습니다."
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "collapsed_sections": [],
      "name": "federated_learning_for_image_classification.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
